Commit 6396fd39 authored by David Johnson's avatar David Johnson Committed by Josh Kunz

Some build sanitization for Josh's unit test.

Mostly, this involves moving our controller's core MUL interaction
(i.e., all the module init and MUL callback stuff) into a separate file,
so we can build the core of controller.c into a lib that we can link
unit tests against.

In general, this whole thing is nasty, because libmulutil requires some
app callback stuff to be defined by whomever is implementing main(), and
of course everybody has to link against libmulutil.  In this case, since
the tests implement main(), we have to do a tiny bit of glue stubs.  The
amount of future glue code will depend on "unit test" paths into the MUL
code... we may have to grow a "test" version of mul_app_main.c, for
instance, or make that into a callable library.  Anyway, stuff for the
future.
parent 8d96cc58
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = include lib controller tools client
SUBDIRS = include lib controller tools client test
......@@ -238,5 +238,6 @@ AC_CONFIG_FILES(
client/Makefile
client/python/Makefile
client/python/setup.py
test/Makefile
)
AC_OUTPUT
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(builddir)/../lib \
${MUL_INCLUDES} $(GLIB_INCLUDES) $(PROTOC_INCLUDES) $(LIBCAP_INCLUDES) -std=gnu99 \
-Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
#lib_LTLIBRARIES = libcapnet-lib.la
lib_LTLIBRARIES = libcapnet-controller.la
bin_PROGRAMS = capnet-controller
LDADD = ../lib/libcapnet-lib.la ${MUL_LIBS} $(GLIB_LIBS) $(PROTOC_LIBS) \
-lpthread -lssl $(LIBCAP_LIBS)
noinst_HEADERS = \
$(top_srcdir)/include/capnet_log.h crc.h controller.h metadata.h dispatch.h \
obj_decl.h obj_internal.h obj.h errors.h
capnet_controller_SOURCES = crc.c \
metadata.c metadata_openstack.c metadata_file.c errors.c \
libcapnet_controller_la_SOURCES = \
crc.c metadata.c metadata_openstack.c metadata_file.c errors.c \
obj_callback.c obj_waiting.c obj_internal.c obj.c dispatch.c \
controller.c mul_app_main.c
controller.c
capnet_controller_SOURCES = \
controller_main.c mul_app_main.c
capnet_controller_LDADD = \
../lib/libcapnet-lib.la libcapnet-controller.la \
${MUL_LIBS} $(GLIB_LIBS) $(PROTOC_LIBS) -lpthread -lssl $(LIBCAP_LIBS)
capnet_controller_CFLAGS = -DMUL_APP_V2_MLAPI -DMUL_APP_VTY
......@@ -2,7 +2,6 @@
#include "capnet_config.h"
#include "capnet_log.h"
#include "mul_common.h"
#include "mul_vty.h"
#include "hash.h"
#include "controller.h"
#include "metadata.h"
......@@ -29,8 +28,6 @@
* the capnet capability protocol. */
#define ETH_P_CAP 0x0809
extern struct mul_app_client_cb cnc_app_cbs;
/* Global Opts */
struct cnc_opts cnc_opts = {
.switch_metadata_dir = "/var/tmp",
......@@ -52,6 +49,11 @@ struct cnc_opts cnc_opts = {
static c_rw_lock_t domain_lock;
static GHashTable *domains = NULL;
void cnc_init(void) {
c_rw_lock_init(&domain_lock);
domains = g_hash_table_new_full(g_str_hash,g_str_equal,NULL,NULL);
}
/**
** Prototypes.
**/
......@@ -679,9 +681,9 @@ finish1:
}
/**
** Callback functions.
** MUL Callback functions.
**/
static int cnc_switch_priv_alloc(void **priv) {
int cnc_switch_priv_alloc(void **priv) {
cn_switch_t **csw = (cn_switch_t **)priv;
int ret = cn_switch_new(csw);
if (ret != 0) { return ret; }
......@@ -690,12 +692,12 @@ static int cnc_switch_priv_alloc(void **priv) {
return ret;
}
static void cnc_switch_priv_free(void *priv) {
void cnc_switch_priv_free(void *priv) {
assert(priv != NULL && "MUL asked to free a NULL pointer");
RPUTs_OBJ(priv, MUL_OWNER);
}
static void cnc_switch_add(mul_switch_t *sw) {
void cnc_switch_add(mul_switch_t *sw) {
cn_switch_t *csw = MUL_PRIV_SWITCH(sw);
/*
......@@ -723,7 +725,7 @@ static void cnc_switch_add(mul_switch_t *sw) {
c_log_debug("Capnet Switch 0x%llx added",(unsigned long long)(sw->dpid));
}
static void cnc_switch_del(mul_switch_t *sw) {
void cnc_switch_del(mul_switch_t *sw) {
cn_switch_t *csw = MUL_PRIV_SWITCH(sw);
c_log_debug("Capnet Switch 0x%llx removed",(unsigned long long)(sw->dpid));
......@@ -1445,7 +1447,7 @@ finish:
cn_obj_unlock(csw);
}
static void cnc_port_add(mul_switch_t *sw, mul_port_t *port) {
void cnc_port_add(mul_switch_t *sw, mul_port_t *port) {
cn_switch_t *csw = MUL_PRIV_SWITCH(sw);
cn_port_t *cport = MUL_PRIV_PORT(port);
cn_obj_lock(csw);
......@@ -1612,7 +1614,7 @@ int cnc_port_pending_notify(uint64_t dpid,uint16_t port_no) {
return rc;
}
static void cnc_port_del(mul_switch_t *sw,mul_port_t *port) {
void cnc_port_del(mul_switch_t *sw,mul_port_t *port) {
cn_switch_t *csw = MUL_PRIV_SWITCH(sw);
cn_port_t *cport = MUL_PRIV_PORT(port);
......@@ -1631,14 +1633,14 @@ static void cnc_port_del(mul_switch_t *sw,mul_port_t *port) {
//cnc_switch_remove_node(csw,cport->node);
}
static int cnc_priv_port_alloc(void **port_ptr) {
int cnc_priv_port_alloc(void **port_ptr) {
cn_port_t **port = (cn_port_t **) port_ptr;
int ret = cn_port_new(port);
RHOLD_OBJ(*port, MUL_OWNER);
return ret;
}
static void cnc_priv_port_free(void *priv) {
void cnc_priv_port_free(void *priv) {
cn_port_t *cport;
assert(priv != NULL && "MUL asked us to free a NULL port!");
......@@ -2256,8 +2258,8 @@ finish:
return;
}
static void cnc_packet_in(mul_switch_t *sw,struct flow *fl,uint32_t inport,
uint32_t buffer_id,uint8_t *raw,size_t pkt_len) {
void cnc_packet_in(mul_switch_t *sw,struct flow *fl,uint32_t inport,
uint32_t buffer_id,uint8_t *raw,size_t pkt_len) {
cn_switch_t *csw = MUL_PRIV_SWITCH(sw);
char *buf;
cn_node_t *in_node;
......@@ -2331,165 +2333,6 @@ finish:
return;
}
static void cnc_core_closed(void) {
c_log_info("%s: ",FN);
return;
}
static void cnc_core_reconn(void) {
c_log_info("%s: ",FN);
mul_register_app_cb(NULL,CNC_APP_NAME,C_APP_ALL_SW,C_APP_ALL_EVENTS,
0,NULL,&cnc_app_cbs);
}
/*
* Callback setup.
*/
struct mul_app_client_cb cnc_app_cbs = {
.switch_priv_alloc = cnc_switch_priv_alloc,
.switch_priv_free = cnc_switch_priv_free,
.switch_add_cb = cnc_switch_add,
.switch_del_cb = cnc_switch_del,
.switch_priv_port_alloc = cnc_priv_port_alloc,
.switch_priv_port_free = cnc_priv_port_free,
.switch_port_add_cb = cnc_port_add,
.switch_port_del_cb = cnc_port_del,
.switch_port_link_chg = NULL,
.switch_port_adm_chg = NULL,
.switch_packet_in = cnc_packet_in,
.core_conn_closed = cnc_core_closed,
.core_conn_reconn = cnc_core_reconn
};
/**
** Module core stuff.
**/
void cnc_module_init(void *base_arg) {
struct event_base *base = base_arg;
c_log_debug("%s: switch metadata dir is %s",FN,cnc_opts.switch_metadata_dir);
c_rw_lock_init(&domain_lock);
domains = g_hash_table_new_full(g_str_hash,g_str_equal,NULL,NULL);
mul_register_app_cb(NULL,CNC_APP_NAME,C_APP_ALL_SW,C_APP_ALL_EVENTS,
0,NULL,&cnc_app_cbs);
cn_init();
return;
}
/**
** getopt options support.
**/
int cnc_getopt_helper(void *priv,int opt,char *optarg) {
struct cnc_opts *opts = (struct cnc_opts *)priv;
char *tok,*tok2;
char *saveptr,*saveptr2;
char *sp,*sp2,*cp;
GList *list;
c_log_debug("%s: opt is %c, optarg is %s",FN,(char)opt,optarg);
switch (opt) {
case 'S':
opts->switch_metadata_dir = strdup(optarg);
break;
case 'W':
cnc_set_warn_level(atoi(optarg));
break;
case 'Z':
cnc_set_log_level(atoi(optarg));
break;
case 'L':
if (cnc_add_log_area_flaglist(optarg,NULL)) {
c_log_err("%s: bad log level flag in '%s'!\n",FN,optarg);
return -1;
}
break;
case 'F':
if (!opts->node_flow_caps)
opts->node_flow_caps =
g_hash_table_new_full(g_str_hash,g_str_equal,NULL,NULL);
sp = optarg;
saveptr = NULL;
while ((tok = strtok_r(sp,";",&saveptr)) != NULL) {
sp = NULL;
cp = index(tok,':');
if (!cp) {
c_log_err("%s: bad node flow cap item '%s'!",FN,tok);
return -1;
}
*cp = '\0';
++cp;
if (*cp == '\0') {
c_log_err("%s: bad node flow cap item at '%s'!",FN,cp - 1);
return -1;
}
sp2 = cp;
saveptr2 = NULL;
while ((tok2 = strtok_r(sp2,",",&saveptr2)) != NULL) {
sp2 = NULL;
list = (GList *)g_hash_table_lookup(opts->node_flow_caps,tok);
list = g_list_append(list,tok2);
g_hash_table_steal(opts->node_flow_caps,list);
g_hash_table_insert(opts->node_flow_caps,tok,list);
}
}
break;
default:
return -1;
}
return 0;
}
static struct option cnc_longopts[] = {
{ "switch-metadata-dir",required_argument,NULL,'S' },
{ "debug-level",required_argument,NULL,'Z' },
{ "warn-level",required_argument,NULL,'W' },
{ "log-flags",required_argument,NULL,'L', },
{ "node-flow-caps",required_argument,NULL,'F', },
};
struct mul_getopt_helper_info cnc_getopt_helper_info = {
.module_init_fn = cnc_module_init,
.module_getopt_helper_fn = cnc_getopt_helper,
.priv = (void *)&cnc_opts,
.opts = "S:Z:W:L:F:",
.longopts = cnc_longopts,
.longopts_len = sizeof(cnc_longopts) / sizeof(struct option),
.usage = \
CNC_APP_NAME " Options:\n" \
"\t-S, --switch-metadata-dir <DIRECTORY>\n" \
"\t\tThe DIRECTORY containing per-datapath-id files describing each\n" \
"\t\tswitch. Each file contains port descriptions.\n" \
"\t-Z, --debug-level <LEVEL>\n" \
"\t\tSet the debug msg level.\n" \
"\t-W, --warn-level <LEVEL>\n" \
"\t\tSet the optional warn msg level.\n" \
"\t-L, --log-flags <FLAGS>\n" \
"\t\tA comma-separated list of debug flags (set to ALL to see all).\n"
"\t-F, --node-flow-caps <src1:dst1,dst2,dst3,...;src2:dst4,dst5,dst6,...;...\n" \
"\t\tA comma-separated list of debug flags (set to ALL to see all).\n",
};
module_getopt_helper(cnc_getopt_helper_info);
/**
** Terminal support.
**/
#ifdef MUL_APP_VTY
void cnc_module_vty_init(void *arg UNUSED) {
c_log_debug("%s:",FN);
}
module_vty_init(cnc_module_vty_init);
#endif
module_init(cnc_module_init);
/**
** Flow logic.
**/
......
......@@ -31,6 +31,8 @@ typedef struct cnc_lan {
} cnc_lan_t;
*/
void cnc_init(void);
void cnc_module_init(void *ctx);
void cnc_module_vty_init(void *arg);
......@@ -67,4 +69,20 @@ int cnc_send_notify(cn_node_t *dest,
*/
int cnc_port_pending_notify(uint64_t dpid,uint16_t port_no);
/**
* MUL callbacks, defined in controller.c and sent to MUL in controller_main.c .
*/
int cnc_switch_priv_alloc(void **priv);
void cnc_switch_priv_free(void *priv);
void cnc_switch_add(mul_switch_t *sw);
void cnc_switch_del(mul_switch_t *sw);
void cnc_port_add(mul_switch_t *sw, mul_port_t *port);
void cnc_port_del(mul_switch_t *sw,mul_port_t *port);
int cnc_priv_port_alloc(void **port_ptr);
void cnc_priv_port_free(void *priv);
void cnc_packet_in(mul_switch_t *sw,struct flow *fl,uint32_t inport,
uint32_t buffer_id,uint8_t *raw,size_t pkt_len);
void cnc_core_closed(void);
void cnc_core_reconn(void);
#endif /* __CAPNET_CONTROLLER_H__ */
#include "capnet_config.h"
#include "capnet_log.h"
#include "mul_common.h"
#include "mul_vty.h"
#include "controller.h"
/* Global Opts */
struct cnc_opts cnc_opts = {
.switch_metadata_dir = "/var/tmp",
/* XXX: id of the port that should be the master. This should come from the
* metadata service, but for now, just hardcode it. */
//.MASTER_node_id = "port-1",
.node_flow_caps = NULL,
};
/*
* Callback setup.
*/
struct mul_app_client_cb cnc_app_cbs = {
.switch_priv_alloc = cnc_switch_priv_alloc,
.switch_priv_free = cnc_switch_priv_free,
.switch_add_cb = cnc_switch_add,
.switch_del_cb = cnc_switch_del,
.switch_priv_port_alloc = cnc_priv_port_alloc,
.switch_priv_port_free = cnc_priv_port_free,
.switch_port_add_cb = cnc_port_add,
.switch_port_del_cb = cnc_port_del,
.switch_port_link_chg = NULL,
.switch_port_adm_chg = NULL,
.switch_packet_in = cnc_packet_in,
.core_conn_closed = cnc_core_closed,
.core_conn_reconn = cnc_core_reconn
};
/**
* A few generic MUL callbacks that don't involve our core controller
* code, for now.
*/
void cnc_core_closed(void) {
c_log_info("%s: ",FN);
return;
}
void cnc_core_reconn(void) {
c_log_info("%s: ",FN);
mul_register_app_cb(NULL,CNC_APP_NAME,C_APP_ALL_SW,C_APP_ALL_EVENTS,
0,NULL,&cnc_app_cbs);
}
/**
** Module core stuff.
**/
void cnc_module_init(void *base_arg) {
struct event_base *base = base_arg;
c_log_debug("%s: switch metadata dir is %s",FN,cnc_opts.switch_metadata_dir);
cnc_init();
mul_register_app_cb(NULL,CNC_APP_NAME,C_APP_ALL_SW,C_APP_ALL_EVENTS,
0,NULL,&cnc_app_cbs);
cn_init();
return;
}
/**
** getopt options support.
**/
int cnc_getopt_helper(void *priv,int opt,char *optarg) {
struct cnc_opts *opts = (struct cnc_opts *)priv;
char *tok,*tok2;
char *saveptr,*saveptr2;
char *sp,*sp2,*cp;
GList *list;
c_log_debug("%s: opt is %c, optarg is %s",FN,(char)opt,optarg);
switch (opt) {
case 'S':
opts->switch_metadata_dir = strdup(optarg);
break;
case 'W':
cnc_set_warn_level(atoi(optarg));
break;
case 'Z':
cnc_set_log_level(atoi(optarg));
break;
case 'L':
if (cnc_add_log_area_flaglist(optarg,NULL)) {
c_log_err("%s: bad log level flag in '%s'!\n",FN,optarg);
return -1;
}
break;
case 'F':
if (!opts->node_flow_caps)
opts->node_flow_caps =
g_hash_table_new_full(g_str_hash,g_str_equal,NULL,NULL);
sp = optarg;
saveptr = NULL;
while ((tok = strtok_r(sp,";",&saveptr)) != NULL) {
sp = NULL;
cp = index(tok,':');
if (!cp) {
c_log_err("%s: bad node flow cap item '%s'!",FN,tok);
return -1;
}
*cp = '\0';
++cp;
if (*cp == '\0') {
c_log_err("%s: bad node flow cap item at '%s'!",FN,cp - 1);
return -1;
}
sp2 = cp;
saveptr2 = NULL;
while ((tok2 = strtok_r(sp2,",",&saveptr2)) != NULL) {
sp2 = NULL;
list = (GList *)g_hash_table_lookup(opts->node_flow_caps,tok);
list = g_list_append(list,tok2);
g_hash_table_steal(opts->node_flow_caps,list);
g_hash_table_insert(opts->node_flow_caps,tok,list);
}
}
break;
default:
return -1;
}
return 0;
}
static struct option cnc_longopts[] = {
{ "switch-metadata-dir",required_argument,NULL,'S' },
{ "debug-level",required_argument,NULL,'Z' },
{ "warn-level",required_argument,NULL,'W' },
{ "log-flags",required_argument,NULL,'L', },
{ "node-flow-caps",required_argument,NULL,'F', },
};
struct mul_getopt_helper_info cnc_getopt_helper_info = {
.module_init_fn = cnc_module_init,
.module_getopt_helper_fn = cnc_getopt_helper,
.priv = (void *)&cnc_opts,
.opts = "S:Z:W:L:F:",
.longopts = cnc_longopts,
.longopts_len = sizeof(cnc_longopts) / sizeof(struct option),
.usage = \
CNC_APP_NAME " Options:\n" \
"\t-S, --switch-metadata-dir <DIRECTORY>\n" \
"\t\tThe DIRECTORY containing per-datapath-id files describing each\n" \
"\t\tswitch. Each file contains port descriptions.\n" \
"\t-Z, --debug-level <LEVEL>\n" \
"\t\tSet the debug msg level.\n" \
"\t-W, --warn-level <LEVEL>\n" \
"\t\tSet the optional warn msg level.\n" \
"\t-L, --log-flags <FLAGS>\n" \
"\t\tA comma-separated list of debug flags (set to ALL to see all).\n"
"\t-F, --node-flow-caps <src1:dst1,dst2,dst3,...;src2:dst4,dst5,dst6,...;...\n" \
"\t\tA comma-separated list of debug flags (set to ALL to see all).\n",
};
module_getopt_helper(cnc_getopt_helper_info);
/**
** Terminal support.
**/
#ifdef MUL_APP_VTY
void cnc_module_vty_init(void *arg UNUSED) {
c_log_debug("%s:",FN);
}
module_vty_init(cnc_module_vty_init);
#endif
module_init(cnc_module_init);
.PHONY: default
include_dir = ../controller
include = $(wildcard $(include_dir)/*.h)
capnet_include_dir = ../../libs/include
capnet_lib_dir = $(shell pwd)/../../libs/lib
controller_src = metadata.c metadata_openstack.c metadata_file.c errors.c \
obj_callback.c obj_waiting.c obj_internal.c obj.c dispatch.c \
controller.c mul_app_main.c
objects = $(patsubst %.c,../capnet.obj/controller/capnet_controller-%.o,$(controller_src))
objects += $(wildcard ../capnet.obj/lib/*.o)
pkg_config_libs = glib-2.0 openssl libevent
CC = clang
CFLAGS = -I$(include_dir) $(shell pkg-config --cflags $(pkg_config_libs))
CFLAGS += -I$(capnet_include_dir)
CFLAGS += -I$(capnet_include_dir)/openmul
CFLAGS += -I../capnet.obj
CFLAGS += -I../capnet.obj/lib
CFLAGS += -g
LDFLAGS = $(shell pkg-config --libs-only-L $(pkg_config_libs))
LDFLAGS += -L$(capnet_lib_dir)
LDFLAGS += -Wl,-etest_main -Wl,-rpath $(capnet_lib_dir)
LDLIBS = $(shell pkg-config --libs-only-l $(pkg_config_libs))
LDLIBS += -lcap -lcapnet-lib -lpthread -lprotobuf-c -lprotobuf -lmul
LDLIBS += -lmultr -lmulutil -lrt -lcli
default: test
test: $(objects) $(include)
$(CC) $(CFLAGS) -o $@ $(filter %.o,$^) $(LDFLAGS) $(LDLIBS) $@.c
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(builddir)/../lib -I$(top_srcdir)/controller \
${MUL_INCLUDES} $(GLIB_INCLUDES) $(PROTOC_INCLUDES) $(LIBCAP_INCLUDES) -std=gnu99 \
-Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
#lib_LTLIBRARIES = libcapnet-lib.la
noinst_PROGRAMS = test
LDADD = ../lib/libcapnet-lib.la ../controller/libcapnet-controller.la \
${MUL_LIBS} $(GLIB_LIBS) $(PROTOC_LIBS) -lpthread -lssl $(LIBCAP_LIBS)
#LDADD = ../lib/libcapnet-lib.la $(GLIB_LIBS) $(PROTOC_LIBS) \
# -lpthread -lssl $(LIBCAP_LIBS) ../controller/libcapnet-controller.la
noinst_HEADERS = \
../controller/dispatch.h ../controller/obj.h
test_SOURCES = \
test.c mul_stubs.c
#test_CFLAGS = -DMUL_APP_V2_MLAPI -DMUL_APP_VTY
#include "mul_common.h"
#include "mul_app_main.h"
#include "mul_app_infra.h"
#include "mul_services.h"
struct mul_app_client_cb *app_cbs = NULL;
struct c_app_service c_app_service_tbl[MUL_MAX_SERVICE_NUM];
......@@ -203,7 +203,7 @@ static char * all_tests(void) {
return NULL;
}
int test_main(void) {
int main(int argc,char **argv) {
cn_init();
char * result = all_tests();
if (result) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment