From d310c9a4b70dd117d15694b9d8055f0e54934a83 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 20 Dec 2017 08:05:41 +0100 Subject: [PATCH 1/5] added install target to CMake --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f025bb6..ba8949e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,11 @@ target_include_directories(netem PUBLIC "/usr/include/libnl3") add_library(mark mark.c) +install(TARGETS netem mark + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static) + set(CPACK_PACKAGE_NAME "netem") set(CPACK_PACKAGE_CONTACT "Steffen Vogel ") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "netem measures and emulates network delay distributions using the NetEm queuing discipline") From 0c8156845dc7241f8878c80ea9910dd5e023fab5 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 20 Dec 2017 08:12:25 +0100 Subject: [PATCH 2/5] whitespace cleanup --- dist-maketable.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dist-maketable.c b/dist-maketable.c index 386b405..b1ec143 100644 --- a/dist-maketable.c +++ b/dist-maketable.c @@ -40,7 +40,7 @@ double * readdoubles(FILE *fp, int *number) x = calloc(limit, sizeof(double)); if (!x) error(-1, 0, "Alloc"); - + size_t linelen = 0; char *line; @@ -48,9 +48,9 @@ double * readdoubles(FILE *fp, int *number) if (getline(&line, &linelen, fp) > 0) { if (line[0] == '#' || line[0] == '\r' || line[0] == '\n') continue; - + fscanf(fp, "%lf", &x[i]); - + ++n; } else if (feof(fp)) @@ -202,7 +202,7 @@ main(int argc, char **argv) } } else { fp = stdin; - } + } x = readdoubles(fp, &limit); if (limit <= 0) { fprintf(stderr, "Nothing much read!\n"); @@ -213,7 +213,7 @@ main(int argc, char **argv) fprintf(stderr, "%d values, mu %10.4f, sigma %10.4f, rho %10.4f\n", limit, mu, sigma, rho); #endif - + table = makedist(x, limit, mu, sigma); free((void *) x); cumulativedist(table, DISTTABLESIZE, &total); @@ -221,4 +221,4 @@ main(int argc, char **argv) interpolatetable(inverse, TABLESIZE); printtable(inverse, TABLESIZE); return 0; -}*/ \ No newline at end of file +}*/ From f4c5826ab03813a5c31f7b16e9e698603ce464b3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 20 Dec 2017 09:50:41 +0100 Subject: [PATCH 3/5] added scaling option to dist subcommand --- config.h | 3 ++- dist.c | 23 ++++++++++++----------- main.c | 28 ++++++++++++++++------------ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/config.h b/config.h index 0398d0d..3991bad 100644 --- a/config.h +++ b/config.h @@ -16,10 +16,11 @@ struct config { int interval; int limit; double rate; + double scaling; char *dev; }; /* Declared in main.c */ extern struct config cfg; -#endif \ No newline at end of file +#endif diff --git a/dist.c b/dist.c index f0baba4..ccda90e 100644 --- a/dist.c +++ b/dist.c @@ -56,30 +56,31 @@ int rtnl_netem_set_delay_distribution_data(struct rtnl_qdisc *qdisc, short *data return 0; } -static short * dist_make(FILE *fp, double *mu, double *sigma, double *rho) +static short * dist_make(FILE *fp, double *mu, double *sigma, double *rho, int *cnt) { - int limit; - double *x; + double *measurements; int *table; short *inverse; int total; - x = readdoubles(fp, &limit); - if (limit <= 0) + measurements = readdoubles(fp, cnt); + if (*cnt <= 0) error(-1, 0, "Nothing much read!"); - arraystats(x, limit, mu, sigma, rho); + for (int i = 0; i < *cnt; i++) + measurements[i] *= cfg.scaling; - fprintf(stderr, "Read %d values, mu %10.4f, sigma %10.4f, rho %10.4f\n", - limit, *mu, *sigma, *rho); - - table = makedist(x, limit, *mu, *sigma); - free((void *) x); + arraystats(measurements, *cnt, mu, sigma, rho); + table = makedist(measurements, *cnt, *mu, *sigma); cumulativedist(table, DISTTABLESIZE, &total); + inverse = inverttable(table, TABLESIZE, DISTTABLESIZE, total); interpolatetable(inverse, TABLESIZE); + free((void *) measurements); + free((void *) table); + return inverse; } diff --git a/main.c b/main.c index e6a2e38..1d479d4 100644 --- a/main.c +++ b/main.c @@ -27,6 +27,7 @@ int running = 1; struct config cfg = { .limit = 100, .rate = 1, + .scaling = 1, .mark = 0xCD, .mask = 0xFFFFFFFF, .dev = "eth0" @@ -43,7 +44,7 @@ void quit(int sig, siginfo_t *si, void *ptr) } int main(int argc, char *argv[]) -{ +{ if (argc < 2) { printf( "usage: %s CMD [OPTIONS]\n" " CMD can be one of:\n\n" @@ -64,12 +65,13 @@ int main(int argc, char *argv[]) " -r --rate rate limit used for measurements and updates of network emulation\n" " -l --limit how many probes should we sent\n" " -d --dev network interface\n" + " -s FACTOR a scaling factor for the dist subcommands\n" "\n" "netem util %s (built on %s %s)\n" " Copyright 2015, Steffen Vogel \n", argv[0], VERSION, __DATE__, __TIME__); exit(EXIT_FAILURE); - } + } /* Setup signals */ struct sigaction sa_quit = { @@ -80,13 +82,13 @@ int main(int argc, char *argv[]) sigemptyset(&sa_quit.sa_mask); sigaction(SIGTERM, &sa_quit, NULL); sigaction(SIGINT, &sa_quit, NULL); - + /* Initialize PRNG for TCP sequence nos */ srand(time(NULL)); - + /* Parse Arguments */ char c, *endptr; - while ((c = getopt (argc-1, argv+1, "h:m:M:i:l:d:r:")) != -1) { + while ((c = getopt(argc, argv, "h:m:M:i:l:d:r:s:")) != -1) { switch (c) { case 'm': cfg.mark = strtoul(optarg, &endptr, 0); @@ -103,11 +105,12 @@ int main(int argc, char *argv[]) case 'l': cfg.limit = strtoul(optarg, &endptr, 10); goto check; - + case 's': + cfg.scaling = strtof(optarg, &endptr); + goto check; case 'd': cfg.dev = strdup(optarg); break; - case '?': if (optopt == 'c') error(-1, 0, "Option -%c requires an argument.", optopt); @@ -115,18 +118,19 @@ int main(int argc, char *argv[]) error(-1, 0, "Unknown option '-%c'.", optopt); else error(-1, 0, "Unknown option character '\\x%x'.", optopt); + exit(EXIT_FAILURE); default: abort(); } - + continue; check: if (optarg == endptr) error(-1, 0, "Failed to parse parse option argument '-%c %s'", c, optarg); } - - char *cmd = argv[1]; + + char *cmd = argv[optind]; if (!strcmp(cmd, "probe")) return probe(argc-optind-1, argv+optind+1); @@ -136,6 +140,6 @@ check: return dist(argc-optind-1, argv+optind+1); else error(-1, 0, "Unknown command: %s", cmd); - + return 0; -} \ No newline at end of file +} From cf998a28567f618dfa16856f0cf1e3b1d82ba480 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 20 Dec 2017 10:16:43 +0100 Subject: [PATCH 4/5] added new output format for VILLASnode --- config.h | 4 ++++ dist-maketable.c | 2 -- dist.c | 41 ++++++++++++++++++++++++++++++++++++++--- main.c | 16 ++++++++++++++-- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/config.h b/config.h index 3991bad..100bef4 100644 --- a/config.h +++ b/config.h @@ -18,6 +18,10 @@ struct config { double rate; double scaling; char *dev; + enum { + FORMAT_TC, + FORMAT_VILLAS + } format; }; /* Declared in main.c */ diff --git a/dist-maketable.c b/dist-maketable.c index b1ec143..a5fc611 100644 --- a/dist-maketable.c +++ b/dist-maketable.c @@ -176,8 +176,6 @@ void printtable(const short *table, int limit) { int i; - printf("# This is the distribution table for the experimental distribution.\n"); - for (i=0 ; i < limit; ++i) { printf("%d%c", table[i], (i % 8) == 7 ? '\n' : ' '); diff --git a/dist.c b/dist.c index ccda90e..33c2a3d 100644 --- a/dist.c +++ b/dist.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -88,6 +90,7 @@ static int dist_generate(int argc, char *argv[]) { FILE *fp; double mu, sigma, rho; + int cnt; if (argc == 1) { if (!(fp = fopen(argv[0], "r"))) @@ -96,11 +99,42 @@ static int dist_generate(int argc, char *argv[]) else fp = stdin; - short *inverse = dist_make(fp, &mu, &sigma, &rho); + short *inverse = dist_make(fp, &mu, &sigma, &rho, &cnt); if (!inverse) error(-1, 0, "Failed to generate distribution"); - printtable(inverse, TABLESIZE); + char date[100], user[100], host[100]; + time_t now = time (0); + strftime(date, sizeof(date), "%Y-%m-%d %H:%M", localtime(&now)); + gethostname(host, sizeof(host)); + getlogin_r(user, sizeof(user)); + + printf("# This is the distribution table for the experimental distribution.\n"); + printf("# Read %d values, mu %.6f, sigma %.6f, rho %.6f\n", cnt, mu, sigma, rho); + printf("# Generated %s, by %s on %s\n", date, user, host); + printf("#\n"); + + switch (cfg.format) { + case FORMAT_TC: + printtable(inverse, TABLESIZE); + break; + + case FORMAT_VILLAS: + printf("netem = {\n"); + printf(" delay = %f\n", mu * 1e6); + printf(" jitter = %f\n", sigma * 1e6); + printf(" distribution = [ %d", inverse[0]); + + for (int i = 1; i < TABLESIZE; i++) + printf(", %d", inverse[i]); + + printf(" ]\n"); + printf(" loss = 0,\n"); + printf(" duplicate = 0,\n"); + printf(" corrupt = 0\n"); + printf(" }\n"); + break; + } return 0; } @@ -109,6 +143,7 @@ static int dist_load(int argc, char *argv[]) { FILE *fp; double mu, sigma, rho; + int cnt; if (argc == 1) { if (!(fp = fopen(argv[0], "r"))) @@ -117,7 +152,7 @@ static int dist_load(int argc, char *argv[]) else fp = stdin; - short *inverse = dist_make(fp, &mu, &sigma, &rho); + short *inverse = dist_make(fp, &mu, &sigma, &rho, &cnt); if (!inverse) error(-1, 0, "Failed to generate distribution"); diff --git a/main.c b/main.c index 1d479d4..e234508 100644 --- a/main.c +++ b/main.c @@ -30,7 +30,8 @@ struct config cfg = { .scaling = 1, .mark = 0xCD, .mask = 0xFFFFFFFF, - .dev = "eth0" + .dev = "eth0", + .format = FORMAT_TC }; int probe(int argc, char *argv[]); @@ -66,6 +67,7 @@ int main(int argc, char *argv[]) " -l --limit how many probes should we sent\n" " -d --dev network interface\n" " -s FACTOR a scaling factor for the dist subcommands\n" + " -f FMT the output format of the distribution tables\n" "\n" "netem util %s (built on %s %s)\n" " Copyright 2015, Steffen Vogel \n", argv[0], VERSION, __DATE__, __TIME__); @@ -88,7 +90,7 @@ int main(int argc, char *argv[]) /* Parse Arguments */ char c, *endptr; - while ((c = getopt(argc, argv, "h:m:M:i:l:d:r:s:")) != -1) { + while ((c = getopt(argc, argv, "h:m:M:i:l:d:r:s:f:")) != -1) { switch (c) { case 'm': cfg.mark = strtoul(optarg, &endptr, 0); @@ -111,6 +113,16 @@ int main(int argc, char *argv[]) case 'd': cfg.dev = strdup(optarg); break; + case 'f': + if (strcmp(optarg, "villas") == 0) + cfg.format = FORMAT_VILLAS; + else if (strcmp(optarg, "tc") == 0) + cfg.format = FORMAT_TC; + else { + error(-1, 0, "Unknown format: %s.", optarg); + exit(EXIT_FAILURE); + } + break; case '?': if (optopt == 'c') error(-1, 0, "Option -%c requires an argument.", optopt); From 764a5e570bca63447d67d177e31f59be5686d23f Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 20 Dec 2017 10:17:48 +0100 Subject: [PATCH 5/5] started fixing TCP checksum claculation n --- probe.c | 77 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/probe.c b/probe.c index 461cc12..9d3a4ce 100644 --- a/probe.c +++ b/probe.c @@ -37,47 +37,72 @@ #include "utils.h" #include "hist.h" -int probe_tcp(int sd, unsigned short dport, struct timespec *ts) +struct phdr { + struct in_addr source; + struct in_addr destination; + uint8_t reserved; + uint8_t protocol; + uint16_t length; +} __attribute__((packed)); + +int probe_tcp(int sd, unsigned short dport, struct in_addr src, struct in_addr dst, struct timespec *ts) { struct timespec ts_syn, ts_ack; - struct iphdr ihdr; - struct tcphdr thdr; + struct phdr *phdr; + struct iphdr *ihdr; + struct tcphdr *thdr; + + char buf[sizeof(struct phdr) + sizeof(struct iphdr) + sizeof(struct tcphdr)]; + struct msghdr msgh; ssize_t len; - struct iovec iov[2] = { - { .iov_base = &ihdr, .iov_len = sizeof(ihdr) }, // IP header - { .iov_base = &thdr, .iov_len = sizeof(thdr) } // TCP header - }; - /* Sending SYN */ - memset(&ihdr, 0, sizeof(ihdr)); - memset(&thdr, 0, sizeof(thdr)); + memset(buf, 0, sizeof(buf)); memset(&msgh, 0, sizeof(msgh)); /* Randomize sequence number and source port */ unsigned int seq = (unsigned) rand(); unsigned short sport = (rand() + 1024) & 0xFFFF; - thdr.syn = 1; - thdr.seq = htonl(seq); - thdr.source = htons(sport); - thdr.dest = htons(dport); - thdr.doff = 5; - thdr.check = tcp_csum((unsigned short *) &thdr, sizeof(thdr)); + phdr = (struct phdr *) buf; + thdr = (struct tcphdr *) (phdr + 1); - msgh.msg_iov = &iov[1]; // only send TCP header + phdr->source = src; + phdr->destination = dst; + phdr->protocol = IPPROTO_TCP; + phdr->length = sizeof(struct tcphdr); + + thdr->syn = 1; + thdr->seq = htonl(seq); + thdr->source = htons(sport); + thdr->dest = htons(dport); + thdr->doff = 5; + thdr->check = tcp_csum((unsigned short *) &phdr, sizeof(struct phdr) + sizeof(struct tcphdr)); + + struct iovec iov1[] = { + { .iov_base = thdr, .iov_len = sizeof(struct tcphdr) } // TCP header + }; + + msgh.msg_iov = iov1; // only send TCP header msgh.msg_iovlen = 1; if (ts_sendmsg(sd, &msgh, 0, &ts_syn) < 0) error(-1, errno, "Failed to send SYN packet"); /* Receiving ACK */ - memset(&ihdr, 0, sizeof(ihdr)); - memset(&thdr, 0, sizeof(thdr)); + memset(buf, 0, sizeof(buf)); - msgh.msg_iov = &iov[0]; // receive IP + TCP header + ihdr = (struct iphdr *) buf; + thdr = (struct tcphdr *) (ihdr + 1); + + struct iovec iov2[] = { + { .iov_base = ihdr, .iov_len = sizeof(struct iphdr) }, // IP header + { .iov_base = thdr, .iov_len = sizeof(struct tcphdr) } // TCP header + }; + + msgh.msg_iov = iov2; // receive IP + TCP header msgh.msg_iovlen = 2; retry: len = ts_recvmsg(sd, &msgh, 0, &ts_ack); @@ -88,15 +113,15 @@ retry: len = ts_recvmsg(sd, &msgh, 0, &ts_ack); // len, thdr.syn, thdr.ack, thdr.rst, ntohl(thdr.seq), ntohl(thdr.ack_seq), ntohs(thdr.source), ntohs(thdr.dest)); /* Check response */ - if (thdr.source != htons(dport) || thdr.dest != htons(sport)) { + if (thdr->source != htons(dport) || thdr->dest != htons(sport)) { printf("Skipping invalid ports\n"); goto retry; } - else if (!thdr.rst && !(thdr.ack && thdr.syn)) { + else if (!thdr->rst && !(thdr->ack && thdr->syn)) { printf("Skipping invalid flags\n"); goto retry; } - else if (ntohl(thdr.ack_seq) != seq + 1) { + else if (ntohl(thdr->ack_seq) != seq + 1) { printf("Skipping invalid seq\n"); goto retry; } @@ -113,6 +138,7 @@ int probe(int argc, char *argv[]) /* Parse address */ struct nl_addr *addr; struct sockaddr_in sin; + struct in_addr src, dst; /* Parse args */ if (argc != 2) @@ -129,6 +155,9 @@ int probe(int argc, char *argv[]) if (nl_addr_fill_sockaddr(addr, (struct sockaddr *) &sin, &sinlen)) error(-1, 0, "Failed to fill sockaddr"); + dst = sin.sin_addr; + inet_aton("134.130.169.31", &src); + /* Create RAW socket */ int sd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); if (sd < 0) @@ -156,7 +185,7 @@ int probe(int argc, char *argv[]) error(-1, errno, "Failed to initilize timer"); do { - probe_tcp(sd, dport, &ts); + probe_tcp(sd, dport, src, dst, &ts); double rtt = time_to_double(&ts); hist_put(&hist, rtt);