Skip to content

Commit

Permalink
Unit-tests and refCounter corrections
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Ekman committed Oct 18, 2022
1 parent 08fe6ff commit d6c6f48
Show file tree
Hide file tree
Showing 6 changed files with 375 additions and 78 deletions.
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ $(IPU): $(LIB) $(IPU_SRC)
$(O)/lib/test/% : lib/test/%.c
$(CC) $(CFLAGS) -Wall -Ilib -pthread $< -o $@ -L$(O)/lib -lnfqlb -lrt -lpcap
$(O)/nfqlb/%-test : nfqlb/%-test.c
$(CC) $(CFLAGS) -Wall -Ilib -pthread $< $(subst -test,,$<) -o $@ -L$(O)/lib -lnfqlb -lrt
$(CC) $(CFLAGS) -Wall -Ilib -pthread $< $(subst -test,,$<) -o $@ -L$(O)/lib -lnfqlb -lnetfilter_queue -lrt -lmnl
TEST_SRC := $(wildcard lib/test/*-test.c) $(wildcard nfqlb/*-test.c)
TEST_PROGS := $(TEST_SRC:%.c=$(O)/%)
$(TEST_PROGS): $(LIB)
Expand Down
19 changes: 19 additions & 0 deletions src/lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,25 @@ void* flowDelete(
return user_ref;
}

void* flowLookupName(
struct FlowSet* set, char const* name, /*out*/unsigned short* udpencap)
{
void* user_ref = NULL;
WLOCK(set);
for (unsigned i = 0; i < set->count; i++) {
if (strncmp(set->flows[i]->name, name, MAX_NAME) == 0) {
user_ref = set->flows[i]->user_ref;
if (set->lock_user_ref != NULL)
set->lock_user_ref(user_ref);
if (udpencap != NULL)
*udpencap = set->flows[i]->udpencap;
break;
}
}
UNLOCK(set);
return user_ref;
}

static int addrInCidr(struct Cidr* cidr, struct in6_addr adr)
{
maskAdr(&adr, cidr->mask);
Expand Down
8 changes: 8 additions & 0 deletions src/lib/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ void* flowLookup(
unsigned l3proto, void const* data, unsigned len, /* (for byte-match) */
/*out*/unsigned short* udpencap);

// Lookup a name.
// If a lock_user_ref() function is defined it will be called while
// the set is locked. It shall be used to ensure that the user_ref is not
// deleted while in use.
// Returns the "user_ref" the name is found, NULL if not.
void* flowLookupName(
struct FlowSet* set, char const* name, /*out*/unsigned short* udpencap);

// Print a flow if name != NULL or the entire set.
// Output is in json format.
void flowSetPrint(
Expand Down
4 changes: 3 additions & 1 deletion src/lib/test/flow-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ int main(int argc, char* argv[])
sprintf(name, "flow%u", i);
sprintf(port, "%u", i + 20);
err = flowDefine(
f, name, 101-i, user_ref++, NULL, port, NULL, NULL, NULL, NULL, 0);
f, name, 101-i, user_ref, NULL, port, NULL, NULL, NULL, NULL, 0);
assert(flowLookupName(f, name, NULL) == user_ref);
user_ref++;
assert(err == NULL);
}
assert(flowSetSize(f) == 100);
Expand Down
230 changes: 230 additions & 0 deletions src/nfqlb/cmdFlowLb-test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#define _GNU_SOURCE
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>

#include <flow.h>
#include <maglevdyn.h>
#include <shmem.h>
#include <nfqueue.h>
#include "nfqlb.h"

extern struct FlowSet* fset;
extern struct LoadBalancer* lblist;
extern void loadbalancerLock(void* user_ref);
extern void loadbalancerRelease(struct LoadBalancer* lb);
extern struct LoadBalancer* loadbalancerFindOrCreate(char const* target);
extern void cmd_set(struct FlowCmd* cmd, int cd);
extern void cmd_delete(struct FlowCmd* cmd, int cd);

// COPIED FROM cmdFlowLb.c. KEEP IN SYNC!
struct LoadBalancer {
struct LoadBalancer* next;
int refCounter;
char* target;
int fd;
struct SharedData* st;
struct MagDataDyn magd;
};

static void initShm(char const* name, int ownFw, unsigned m, unsigned n);
static int countLb(void);
static int readResult(int fd);

int main(int argc, char* argv[])
{
struct LoadBalancer* lb;
struct FlowCmd cmd;
int pipe[2];
char* protocols[2];

// Init
shm_unlink("lb100");
shm_unlink("lb200");
assert(pipe2(pipe, O_NONBLOCK) == 0);
fset = flowSetCreate(loadbalancerLock);

// LB handling
assert(lblist == NULL);
assert(loadbalancerFindOrCreate("lb100") == NULL);
initShm("lb100", 0, 17, 2);
initShm("lb200", 0, 17, 2);
lb = loadbalancerFindOrCreate("lb100");
assert(lb != NULL);
assert(countLb() == 1);
loadbalancerRelease(lb);
assert(countLb() == 0);

lb = loadbalancerFindOrCreate("lb100");
assert(lb != NULL);
assert(loadbalancerFindOrCreate("lb100") == lb);
assert(countLb() == 1);
loadbalancerRelease(lb);
assert(countLb() == 1);
loadbalancerRelease(lb);
assert(countLb() == 0);

// Flows
memset(&cmd, 0, sizeof(cmd));
cmd.name = "lb100";
cmd.target = "lb100";
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 1);

// Re-define must not increment the refCounter (issue #9)
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);

cmd.name = "lb100-2";
cmd_set(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 1);
assert(lblist->refCounter == 2);

cmd_delete(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 1);
assert(lblist->refCounter == 1);

cmd.name = "lb100";
cmd_delete(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 0);
assert(lblist == NULL);

// Flows with udpencap
memset(&cmd, 0, sizeof(cmd));
cmd.name = "lb100";
cmd.target = "lb100";
protocols[0] = "sctp";
protocols[1] = NULL;
cmd.protocols = (const char**)protocols;
cmd.dports = "2000";
cmd.udpencap = 9000;
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 2);

cmd_delete(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 0);
assert(lblist == NULL);
assert(flowSetSize(fset) == 0);

// Re-define a udpencap and delete
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 2);

cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 2);

cmd_delete(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 0);
assert(lblist == NULL);
assert(flowSetSize(fset) == 0);

// Re-define the upd-port should fail
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 2);

cmd.udpencap = 8000;
cmd_set(&cmd, pipe[1]);
assert(readResult(pipe[0]) != 0);

cmd_delete(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 0);
assert(lblist == NULL);
assert(flowSetSize(fset) == 0);

// Target re-define
memset(&cmd, 0, sizeof(cmd));
cmd.name = "lb100";
cmd.target = "lb100";
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 1);

cmd.target = "WRONG";
cmd_set(&cmd, pipe[1]);
assert(readResult(pipe[0]) != 0);
assert(lblist->refCounter == 1);
assert(flowSetSize(fset) == 1);
assert(countLb() == 1);

cmd.target = "lb200";
cmd_set(&cmd, pipe[1]);
assert(countLb() == 1);
assert(lblist->refCounter == 1);
assert(readResult(pipe[0]) == 0);
assert(flowSetSize(fset) == 1);

cmd_delete(&cmd, pipe[1]);
assert(readResult(pipe[0]) == 0);
assert(countLb() == 0);
assert(lblist == NULL);
assert(flowSetSize(fset) == 0);

// Clean-up
assert(shm_unlink("lb100") == 0);
assert(shm_unlink("lb200") == 0);
printf("=== cmdFlowLb-test; OK\n");
return 0;
}

static int readResult(int fd)
{
char buff[64];
int rc = read(fd, buff, sizeof(buff));
//printf("rc=%d, response [%s]\n", rc, buff);
if (rc < 3) return -1;
if (rc > 3) printf("response [%s], rc=%d\n", buff, rc);
if (strncmp(buff, "OK", 2) != 0)
return -1;
return 0;
}

static int countLb(void)
{
int cnt = 0;
struct LoadBalancer* lb;
for (lb = lblist; lb != NULL; lb = lb->next) cnt++;
return cnt;
}

static void initShm(
char const* name, int ownFw, unsigned m, unsigned n)
{
unsigned len = magDataDyn_len(m, n);
struct SharedData* s = malloc(sizeof(struct SharedData) + len);
s->ownFwmark = ownFw;
createSharedDataOrDie(name, s, sizeof(struct SharedData) + len);
free(s);
s = mapSharedDataOrDie(name, O_RDWR);
magDataDyn_init(m, n, s->mem, len);
}

void freeFlowCmd(struct FlowCmd* cmd){}
int readFlowCmd(FILE* in, struct FlowCmd* cmd) { return 0; }
Loading

0 comments on commit d6c6f48

Please sign in to comment.