diff --git a/dist.c b/dist.c index 784eacf..f0baba4 100644 --- a/dist.c +++ b/dist.c @@ -5,12 +5,14 @@ * - https://github.com/thom311/libnl/blob/master/lib/route/qdisc/netem.c * * @author Steffen Vogel - * @copyright 2014-2015, Steffen Vogel + * @copyright 2014-2015, Steffen Vogel * @license GPLv3 *********************************************************************************/ -#define _POSIX_C_SOURCE 1 +#define _POSIX_C_SOURCE 200112L #include +#include +#include #include #include @@ -38,20 +40,20 @@ int rtnl_netem_set_delay_distribution_data(struct rtnl_qdisc *qdisc, short *data if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) BUG(); - + if (len > MAXDIST) return -NLE_INVAL; netem->qnm_dist.dist_data = (int16_t *) calloc(len, sizeof(int16_t)); - - size_t i; + + size_t i; for (i = 0; i < len; i++) netem->qnm_dist.dist_data[i] = data[i]; - + netem->qnm_dist.dist_size = len; netem->qnm_mask |= SCH_NETEM_ATTR_DIST; - return 0; + return 0; } static short * dist_make(FILE *fp, double *mu, double *sigma, double *rho) @@ -70,14 +72,14 @@ static short * dist_make(FILE *fp, double *mu, double *sigma, double *rho) 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); cumulativedist(table, DISTTABLESIZE, &total); inverse = inverttable(table, TABLESIZE, DISTTABLESIZE, total); interpolatetable(inverse, TABLESIZE); - + return inverse; } @@ -117,11 +119,11 @@ static int dist_load(int argc, char *argv[]) short *inverse = dist_make(fp, &mu, &sigma, &rho); if (!inverse) error(-1, 0, "Failed to generate distribution"); - + int ret; struct nl_sock *sock; - + struct rtnl_link *link; struct rtnl_tc *qdisc_prio = NULL; struct rtnl_tc *qdisc_netem = NULL; @@ -130,33 +132,33 @@ static int dist_load(int argc, char *argv[]) /* Create connection to netlink */ sock = nl_socket_alloc(); nl_connect(sock, NETLINK_ROUTE); - + /* Get interface */ link = tc_get_link(sock, cfg.dev); if (!link) error(-1, 0, "Interface does not exist: %s", cfg.dev); - + /* Reset TC subsystem */ ret = tc_reset(sock, link); if (ret && ret != -NLE_OBJ_NOTFOUND) error(-1, 0, "Failed to reset TC: %s", nl_geterror(ret)); - + /* Setup TC subsystem */ if ((ret = tc_prio(sock, link, &qdisc_prio))) error(-1, 0, "Failed to setup TC: prio qdisc: %s", nl_geterror(ret)); if ((ret = tc_classifier(sock, link, &cls_fw, cfg.mark, cfg.mask))) error(-1, 0, "Failed to setup TC: fw filter: %s", nl_geterror(ret)); - + if ((ret = tc_netem(sock, link, &qdisc_netem))) error(-1, 0, "Failed to setup TC: netem qdisc: %s", nl_geterror(ret)); - + /* We will use the default normal distribution for now */ if (rtnl_netem_set_delay_distribution_data((struct rtnl_qdisc *) qdisc_netem, inverse, TABLESIZE)) error(-1, 0, "Failed to set netem delay distrubtion: %s", nl_geterror(ret)); - + rtnl_netem_set_delay((struct rtnl_qdisc *) qdisc_netem, mu); - rtnl_netem_set_jitter((struct rtnl_qdisc *) qdisc_netem, sigma); + rtnl_netem_set_jitter((struct rtnl_qdisc *) qdisc_netem, sigma); nl_close(sock); nl_socket_free(sock); @@ -170,11 +172,11 @@ int dist(int argc, char *argv[]) if (argc != 1) error(-1, 0, "Missing sub-command"); - + if (!strcmp(subcmd, "generate")) return dist_generate(argc-1, argv+1); else if (!strcmp(subcmd, "load")) return dist_load(argc-1, argv+1); else return -1; -} \ No newline at end of file +} diff --git a/probe.c b/probe.c index ecb7484..461cc12 100644 --- a/probe.c +++ b/probe.c @@ -1,12 +1,12 @@ /** Probing for RTT, Loss, Duplication, Corruption. * * @author Steffen Vogel - * @copyright 2014-2015, Steffen Vogel + * @copyright 2014-2015, Steffen Vogel * @license GPLv3 *********************************************************************************/ #define _POSIX_C_SOURCE 199309L -#define _BSD_SOURCE +#define _DEFAULT_SOURCE #include #include @@ -40,7 +40,7 @@ int probe_tcp(int sd, unsigned short dport, struct timespec *ts) { struct timespec ts_syn, ts_ack; - + struct iphdr ihdr; struct tcphdr thdr; struct msghdr msgh; @@ -55,38 +55,38 @@ int probe_tcp(int sd, unsigned short dport, struct timespec *ts) memset(&ihdr, 0, sizeof(ihdr)); memset(&thdr, 0, sizeof(thdr)); 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.source = htons(sport); thdr.dest = htons(dport); thdr.doff = 5; thdr.check = tcp_csum((unsigned short *) &thdr, sizeof(thdr)); - + msgh.msg_iov = &iov[1]; // 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)); msgh.msg_iov = &iov[0]; // receive IP + TCP header msgh.msg_iovlen = 2; - + retry: len = ts_recvmsg(sd, &msgh, 0, &ts_ack); if (len < 0) error(-1, 0, "Failed to receive ACK / RST packet"); //printf("TCP: len=%u, syn=%u, ack=%u, rst=%u, seq=%u, ack_seq=%u, src=%u, dst=%u\n", // 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)) { printf("Skipping invalid ports\n"); @@ -100,40 +100,40 @@ retry: len = ts_recvmsg(sd, &msgh, 0, &ts_ack); printf("Skipping invalid seq\n"); goto retry; } - + *ts = time_diff(&ts_syn, &ts_ack); - + return 0; } int probe(int argc, char *argv[]) { int run = 0, tfd; - + /* Parse address */ struct nl_addr *addr; struct sockaddr_in sin; - + /* Parse args */ if (argc != 2) error(-1, 0, "usage: netem probe IP PORT"); - + if (nl_addr_parse(argv[0], AF_UNSPEC, &addr)) error(-1, 0, "Failed to parse address: %s", argv[0]); - + unsigned short dport = atoi(argv[1]); if (!dport) error(-1, 0, "Failed to parse port: %s", argv[1]); - + socklen_t sinlen = sizeof(sin); if (nl_addr_fill_sockaddr(addr, (struct sockaddr *) &sin, &sinlen)) error(-1, 0, "Failed to fill sockaddr"); - + /* Create RAW socket */ int sd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); if (sd < 0) error(-1, errno, "Failed to create socket"); - + /* Bind socket to destination */ if (connect(sd, (struct sockaddr *) &sin, sizeof(sin))) error(-1, 0, "Failed to connect socket"); @@ -143,27 +143,27 @@ int probe(int argc, char *argv[]) fprintf(stderr, "Failed to enable timestamping: %s\n", strerror(errno)); if (ts_enable_sd(sd)) fprintf(stderr, "Failed to set SO_TIMESTAMPING: %s\n", strerror(errno)); - + /* Prepare payload */ struct timespec ts; - + /* Prepare statistics */ struct hist hist; hist_create(&hist, 0, 0, 1); - + /* Start timer */ if ((tfd = timerfd_init(cfg.rate)) < 0) error(-1, errno, "Failed to initilize timer"); - - do { + + do { probe_tcp(sd, dport, &ts); double rtt = time_to_double(&ts); hist_put(&hist, rtt); - + //printf("n=%u, rtt=%f, min=%f, max=%f, avg=%f, stddev=%f\n", // hist.total, rtt, hist.lowest, hist.highest, hist_mean(&hist), hist_stddev(&hist)); - + /* Warmup: adjust histogram after rough estimation of RTT */ if (run == 20) { double span = hist.highest - hist.lowest; @@ -179,20 +179,20 @@ int probe(int argc, char *argv[]) nl_addr2str(addr, addrs, sizeof(addrs)); strftime(date, sizeof(date), "%a, %d %b %Y %T %z", tm); - + printf("# Probing: %s on port %u\n", addrs, dport); printf("# Started: %s\n", date); printf("# RTT mu sigma (units in S)\n"); } - + printf("%f %f %f\n", rtt, hist_mean(&hist), hist_stddev(&hist)); fflush(stdout); run += timerfd_wait(tfd); } while (cfg.limit && run < cfg.limit); - + hist_print(&hist, stderr); hist_destroy(&hist); return 0; -} \ No newline at end of file +} diff --git a/tc.c b/tc.c index edf2bf3..2bcb579 100644 --- a/tc.c +++ b/tc.c @@ -1,12 +1,14 @@ /** Trafic Controller (TC) related functions * * @author Steffen Vogel - * @copyright 2014-2015, Steffen Vogel + * @copyright 2014-2015, Steffen Vogel * @license GPLv3 *********************************************************************************/ -#define _POSIX_C_SOURCE 1 +#define _POSIX_C_SOURCE 200112L #include +#include +#include #include #include @@ -41,7 +43,7 @@ int tc_prio(struct nl_sock *sock, struct rtnl_link *link, struct rtnl_tc **tc) rtnl_tc_set_link(TC_CAST(q), link); rtnl_tc_set_parent(TC_CAST(q), TC_H_ROOT); rtnl_tc_set_handle(TC_CAST(q), TC_HANDLE(1, 0)); - rtnl_tc_set_kind(TC_CAST(q), "prio"); + rtnl_tc_set_kind(TC_CAST(q), "prio"); rtnl_qdisc_prio_set_bands(q, 3+1); rtnl_qdisc_prio_set_priomap(q, map, 7); @@ -49,14 +51,14 @@ int tc_prio(struct nl_sock *sock, struct rtnl_link *link, struct rtnl_tc **tc) int ret = rtnl_qdisc_add(sock, q, NLM_F_CREATE); *tc = TC_CAST(q); - + return ret; } int tc_netem(struct nl_sock *sock, struct rtnl_link *link, struct rtnl_tc **tc) { struct rtnl_qdisc *q; - + if (*tc == NULL) { q = rtnl_qdisc_alloc(); @@ -71,7 +73,7 @@ int tc_netem(struct nl_sock *sock, struct rtnl_link *link, struct rtnl_tc **tc) int ret = rtnl_qdisc_add(sock, q, NLM_F_CREATE); *tc = TC_CAST(q); - + return ret; } @@ -81,17 +83,17 @@ int tc_classifier(struct nl_sock *sock, struct rtnl_link *link, struct rtnl_tc * rtnl_tc_set_link(TC_CAST(c), link); rtnl_tc_set_handle(TC_CAST(c), mark); - rtnl_tc_set_kind(TC_CAST(c), "fw"); + rtnl_tc_set_kind(TC_CAST(c), "fw"); rtnl_cls_set_protocol(c, ETH_P_ALL); - + rtnl_fw_set_classid(c, TC_HANDLE(1, 1)); rtnl_fw_set_mask(c, mask); int ret = rtnl_cls_add(sock, c, NLM_F_CREATE); *tc = TC_CAST(c); - + return ret; } @@ -102,81 +104,81 @@ int tc_reset(struct nl_sock *sock, struct rtnl_link *link) /* Restore default qdisc by deleting the root qdisc (see tc-pfifo_fast(8)) */ rtnl_tc_set_link(TC_CAST(q), link); rtnl_tc_set_parent(TC_CAST(q), TC_H_ROOT); - - int ret = rtnl_qdisc_delete(sock, q); + + int ret = rtnl_qdisc_delete(sock, q); rtnl_qdisc_put(q); - + return ret; } int tc_get_stats(struct nl_sock *sock, struct rtnl_tc *tc, struct tc_stats *stats) { uint64_t *counters = (uint64_t *) stats; - + struct nl_cache *cache; - + rtnl_qdisc_alloc_cache(sock, &cache); - + for (int i = 0; i <= RTNL_TC_STATS_MAX; i++) counters[i] = rtnl_tc_get_stat(tc, i); - + nl_cache_free(cache); return 0; } -int tc_print_stats(struct tc_statistics *stats) +void tc_print_stats(struct tc_statistics *stats) { - printf("packets %u bytes %u\n", stats->packets, stats->bytes); + printf("packets %lu bytes %lu\n", stats->packets, stats->bytes); } int tc_print_netem(struct rtnl_tc *tc) { struct rtnl_qdisc *ne = (struct rtnl_qdisc *) tc; - + if (rtnl_netem_get_limit(ne) > 0) printf("limit %upkts", rtnl_netem_get_limit(ne)); if (rtnl_netem_get_delay(ne) > 0) { printf("delay %fms ", rtnl_netem_get_delay(ne) / 1000.0); - + if (rtnl_netem_get_jitter(ne) > 0) { printf("jitter %fms ", rtnl_netem_get_jitter(ne) / 1000.0); - + if (rtnl_netem_get_delay_correlation(ne) > 0) printf("%u%% ", rtnl_netem_get_delay_correlation(ne)); } } - + if (rtnl_netem_get_loss(ne) > 0) { printf("loss %u%% ", rtnl_netem_get_loss(ne)); - + if (rtnl_netem_get_loss_correlation(ne) > 0) printf("%u%% ", rtnl_netem_get_loss_correlation(ne)); } - + if (rtnl_netem_get_reorder_probability(ne) > 0) { printf(" reorder%u%% ", rtnl_netem_get_reorder_probability(ne)); - + if (rtnl_netem_get_reorder_correlation(ne) > 0) printf("%u%% ", rtnl_netem_get_reorder_correlation(ne)); } - + if (rtnl_netem_get_corruption_probability(ne) > 0) { printf("corruption %u%% ", rtnl_netem_get_corruption_probability(ne)); - + if (rtnl_netem_get_corruption_correlation(ne) > 0) printf("%u%% ", rtnl_netem_get_corruption_correlation(ne)); } - + if (rtnl_netem_get_duplicate(ne) > 0) { printf("duplication %u%% ", rtnl_netem_get_duplicate(ne)); - + if (rtnl_netem_get_duplicate_correlation(ne) > 0) printf("%u%% ", rtnl_netem_get_duplicate_correlation(ne)); } - + printf("\n"); - + return 0; } diff --git a/tc.h b/tc.h index e8c0fe0..84b3dc2 100644 --- a/tc.h +++ b/tc.h @@ -1,7 +1,7 @@ /** Trafic Controller (TC) related functions * * @author Steffen Vogel - * @copyright 2014-2015, Steffen Vogel + * @copyright 2014-2015, Steffen Vogel * @license GPLv3 *********************************************************************************/ @@ -21,7 +21,7 @@ struct tc_statistics { uint64_t backlog; // Current backlog length. uint64_t drops; // Total number of packets dropped. uint64_t requeues; // Total number of requeues. - uint64_t overlimits; // Total number of overlimits. + uint64_t overlimits; // Total number of overlimits. }; struct rtnl_link * tc_get_link(struct nl_sock *sock, const char *dev); @@ -36,7 +36,7 @@ int tc_reset(struct nl_sock *sock, struct rtnl_link *link); int tc_get_stats(struct nl_sock *sock, struct rtnl_tc *tc, struct tc_stats *stats); -int tc_print_stats(struct tc_statistics *stats); +void tc_print_stats(struct tc_statistics *stats); int tc_print_netem(struct rtnl_tc *tc);