First commit
62
BENCHMARKING/README.md
Normal file
@ -0,0 +1,62 @@
|
||||
# Benchmarking
|
||||
|
||||
This section provides the script to launch and reproduce the benchmarks perfromed for this project (and whoses results are posted on the root README file).
|
||||
|
||||
## Preparing the environment
|
||||
|
||||
Prior to launching the benchmarks, you must launch the [pre deployment script](https://git.cetic.be/stages/unikernels/blob/feature/stagelongree2018/DEPLOYMENT/pre_deployment_installation.sh) provided in the DEPLOYMENT folder.
|
||||
|
||||
Then you must install the benchmarking tools using the [install\_bench\_tools.sh](https://git.cetic.be/stages/unikernels/blob/feature/stagelongree2018/BENCHMARKING/install_bench_tools.sh) script.
|
||||
This script will install the following tools:
|
||||
* dnsperf and its dependencies for the DNS benchmark (by Nominum)
|
||||
* wrk2 for the web server benchmark (by Gil Tene, based on original wrk by Will Glozer)
|
||||
|
||||
## Launching the target instance
|
||||
|
||||
To launch an instance to benchmark, launch the **bench_*.sh** scripts:
|
||||
* bench\_container\_dns.sh
|
||||
* bench\_container\_web.sh
|
||||
* bench\_unikernel\_dns.sh
|
||||
* bench\_unikernel\_web.sh
|
||||
|
||||
The scripts will:
|
||||
* build the unikernel/container
|
||||
* stop all running VMs and containers
|
||||
* launch the unikernel/container, attaching it to the default network
|
||||
|
||||
If you're launching a container, the ports will be mapped on launch.
|
||||
If you're launching a unikernel, two rules will be inserted in iptables to allow port forwarding to the internal network.
|
||||
|
||||
## Launching the benchmark
|
||||
|
||||
The benchmark scripts are written in python and make use of the tools installed with the install\_bench\_tools.sh script.
|
||||
|
||||
The web and DNS server benchmarking scripts are written to use 4 threads and simulate 100 virtual connections to the target server.
|
||||
|
||||
### Web server benchmark
|
||||
|
||||
To launch the web server, user `python3 web_unik_benchmark.py [server_ip_address]`.
|
||||
|
||||
The benchmark will send HTTP requests to the server for 5 minutes, starting at a pace of 100 queries per second. After 5 minutes it will save the data in a .csv file and then will relaunch the process incrementing by another 100 queries per second.
|
||||
|
||||
### DNS server benchmark
|
||||
|
||||
To launch the web server, user `python3 web_<type>_benchmark.py [server_ip_address]`.
|
||||
|
||||
The benchmark will send DNS requests to the server for 5 minutes, starting at a pace of 100 queries per second. After 5 minutes it will save the data in a .csv file and then will relaunch the process incrementing by another 100 queries per second.
|
||||
|
||||
### Boot time benchmark
|
||||
|
||||
To launch the web server, user `python3 startup_<type>_benchmark.py [starting number of instances]`.
|
||||
|
||||
The benchmark will start by building and launching the given number of VM or container instances. Then, for 20 minutes, it will send the stop a random instance, send the start command and calculate the time between the start command being sent, and when the target instance responds to a single ping. For each stop/start process, the recorded time is then inserted into a csv file. After 20 minutes, the number of instances is incremented by 10 and the process is repeated. This process repeats itself until 140 instances are launched.
|
||||
|
||||
## Cleaning up the environment
|
||||
|
||||
The individual instance scripts do not stop the instances launched, this needs to be done manually.
|
||||
|
||||
However, each instance start script will stop the currently running containers and virtual machines, as will the boot time benchmark scripts.
|
||||
|
||||
To clean up the iptable rules created for the unikernels use the `./bench_unikernel_cleanup.sh` script.
|
||||
|
||||
To clean up all the instances and iptable rule use the `./cleanup_all.sh` script.
|
BIN
BENCHMARKING/RESULTS/combined.xlsx
Normal file
28
BENCHMARKING/RESULTS/dns_cont_benchmark.csv
Normal file
@ -0,0 +1,28 @@
|
||||
TEST_RUN,QUERIES_SENT,QUERIES_COMPLETED,QUERIES_LOST,QUERIES_PER_SECOND,AVG_LATENCY_SECONDS,MIN,MAX,LATENCY_STD_DEV_SECONDS
|
||||
1,30300,30300,0,100.999942,0.000435,0.000677,0.038042,0.000463
|
||||
2,60600,60600,0,201.999868,0.000413,0.000548,0.045776,0.000575
|
||||
3,90900,90900,0,302.999799,0.000410,0.000522,0.045355,0.000601
|
||||
4,120000,120000,0,399.999763,0.000469,0.000531,0.047507,0.000620
|
||||
5,150300,150300,0,500.999641,0.000401,0.000499,0.050776,0.000639
|
||||
6,180600,180600,0,601.999573,0.000399,0.000448,0.048009,0.000649
|
||||
7,210900,210900,0,702.999531,0.000397,0.000436,0.048220,0.000649
|
||||
8,240000,240000,0,799.999397,0.000457,0.000530,0.050598,0.000664
|
||||
9,270300,270300,0,900.999381,0.000405,0.000447,0.049469,0.000682
|
||||
10,300600,300600,0,1001.999476,0.000387,0.000452,0.048770,0.000673
|
||||
11,330900,330900,0,1102.999158,0.000385,0.000463,0.051058,0.000625
|
||||
12,360000,360000,0,1199.999244,0.000468,0.000455,0.064912,0.000742
|
||||
13,390300,390300,0,1300.999553,0.000407,0.000430,0.053302,0.000715
|
||||
14,420600,420600,0,1401.999248,0.000368,0.000443,0.050178,0.000646
|
||||
15,450900,450900,0,1502.999083,0.000398,0.000420,0.049944,0.000696
|
||||
16,480000,480000,0,1599.998837,0.000477,0.000455,0.062380,0.000803
|
||||
17,510300,510300,0,1700.998883,0.000386,0.000421,0.051476,0.000672
|
||||
18,540600,540600,0,1801.998793,0.000376,0.000405,0.061594,0.000691
|
||||
19,570900,570900,0,1902.998744,0.000401,0.000392,0.074226,0.000725
|
||||
20,600000,600000,0,1999.999260,0.000446,0.000447,0.060142,0.000730
|
||||
21,630300,630300,0,2100.998823,0.000386,0.000388,0.055958,0.000697
|
||||
22,660600,660600,0,2201.998349,0.000384,0.000394,0.063996,0.000722
|
||||
23,690900,690900,0,2302.998572,0.000389,0.000395,0.052586,0.000711
|
||||
24,720000,720000,0,2399.998472,0.000435,0.000440,0.057137,0.000699
|
||||
25,750300,750300,0,2500.998533,0.000402,0.000391,0.072312,0.000743
|
||||
26,780600,780600,0,2601.998439,0.000385,0.000389,0.064135,0.000734
|
||||
27,810900,810900,0,2702.998423,0.000386,0.000393,0.073673,0.000745
|
|
28
BENCHMARKING/RESULTS/dns_unik_benchmark.csv
Normal file
@ -0,0 +1,28 @@
|
||||
TEST_RUN,QUERIES_SENT,QUERIES_COMPLETED,QUERIES_LOST,QUERIES_PER_SECOND,AVG_LATENCY_SECONDS,MIN,MAX,LATENCY_STD_DEV_SECONDS
|
||||
1,30300,30300,0,100.999941,0.006355,0.005415,0.098812,0.002519
|
||||
2,60600,60600,0,201.999860,0.005617,0.005722,0.080283,0.002087
|
||||
3,90900,90900,0,302.999889,0.005715,0.005411,0.101761,0.002100
|
||||
4,120000,120000,0,399.999672,0.006401,0.005320,0.158964,0.001903
|
||||
5,150300,150300,0,500.999711,0.005402,0.004774,0.271349,0.003626
|
||||
6,180600,180600,0,601.999603,0.006268,0.004755,0.725090,0.007226
|
||||
7,210900,210900,0,702.999536,0.011069,0.004425,0.618359,0.015394
|
||||
8,240000,240000,0,799.937413,0.037150,0.004729,0.615609,0.036375
|
||||
9,253892,253892,0,846.044238,0.118990,0.041761,8.319091,0.055582
|
||||
10,255867,255867,0,852.822877,0.118098,0.046127,5.168513,0.024260
|
||||
11,255428,255428,0,851.255666,0.118290,0.046994,4.080020,0.019123
|
||||
12,253791,253791,0,845.691776,0.119118,0.046585,7.608933,0.036147
|
||||
13,254861,254861,0,849.297151,0.118604,0.042165,4.014139,0.018720
|
||||
14,254055,254055,0,846.612175,0.118889,0.037720,7.076644,0.033647
|
||||
15,255951,255951,0,852.928016,0.118049,0.035549,0.581656,0.006604
|
||||
16,254741,254741,0,849.026353,0.118526,0.044648,2.758404,0.013401
|
||||
17,255579,255579,0,851.654708,0.118254,0.037696,0.587303,0.006576
|
||||
18,250233,250233,0,834.063092,0.120648,0.050919,6.691459,0.042768
|
||||
19,253722,253722,0,845.695581,0.119023,0.051268,0.693072,0.007301
|
||||
20,252384,252384,0,841.134621,0.119705,0.042426,7.830838,0.039162
|
||||
21,255698,255698,0,852.217853,0.118158,0.043026,0.596498,0.006608
|
||||
22,251706,251706,0,838.762075,0.120080,0.042971,7.658614,0.042178
|
||||
23,254452,254452,0,848.033594,0.118793,0.047975,0.570417,0.006341
|
||||
24,252446,252446,0,841.183336,0.119791,0.046854,7.977354,0.037990
|
||||
25,253242,253242,0,843.946885,0.119344,0.046943,0.708790,0.006546
|
||||
26,252173,252173,0,840.376755,0.119819,0.049304,6.509316,0.030894
|
||||
27,250928,250928,0,836.353101,0.120345,0.042280,6.734916,0.037482
|
|
1068
BENCHMARKING/RESULTS/startup_cont_benchmark.csv
Normal file
2681
BENCHMARKING/RESULTS/startup_unik_benchmark.csv
Normal file
53
BENCHMARKING/RESULTS/web_apache_cont_benchmark.csv
Normal file
@ -0,0 +1,53 @@
|
||||
TEST_RUN,QUERIES_SENT,QUERIES_PER_SECOND,AVG_LATENCY_MILLISECONDS,MAX_LATENCY_MILLISECONDS,LATENCY_STD_DEV_PERCENT
|
||||
1,30004,100.01,1.52,15.04,1.22
|
||||
2,60004,200.01,5.53,98.24,15.26
|
||||
3,86523,errors:,10.34,86.59,17.49
|
||||
4,97188,errors:,14.77,100.48,21.82
|
||||
5,150004,500.01,1.35,15.90,0.85
|
||||
6,180004,600.01,1.29,11.84,772.32
|
||||
7,210004,700.01,1.33,12.25,814.78
|
||||
8,240004,800.01,1.32,16.99,835.06
|
||||
9,269992,899.97,1.41,15.10,0.89
|
||||
10,299965,999.88,1.61,43.87,1.16
|
||||
11,329977,1099.92,1.31,19.14,0.86
|
||||
12,359967,1199.89,1.30,16.26,0.86
|
||||
13,308094,errors:,1.72,51.23,2.43
|
||||
14,419961,1399.86,1.28,16.22,0.85
|
||||
15,449957,1499.86,1.30,16.86,0.91
|
||||
16,479956,1599.84,1.27,18.67,0.90
|
||||
17,509947,1699.82,1.47,18.24,1.02
|
||||
18,539937,1799.79,1.35,20.96,0.95
|
||||
19,518643,errors:,1.53,48.03,2.09
|
||||
20,599924,1999.74,1.48,15.46,1.04
|
||||
21,456201,errors:,2.73,55.87,3.63
|
||||
22,659914,2199.70,1.36,20.53,1.02
|
||||
23,689901,2299.67,1.31,18.86,0.97
|
||||
24,463255,errors:,2.63,64.32,3.49
|
||||
25,749893,2499.64,1.44,18.54,1.06
|
||||
26,779887,2599.62,1.32,18.93,0.98
|
||||
27,710465,errors:,2.13,64.99,3.10
|
||||
28,839872,2799.58,1.46,24.35,1.09
|
||||
29,869872,2899.56,2.28,1.00,23.82
|
||||
30,753759,errors:,1.85,57.95,2.51
|
||||
31,929856,3099.52,1.35,22.18,1.08
|
||||
32,959839,3199.46,1.49,23.01,1.16
|
||||
33,940349,errors:,2.46,73.92,3.68
|
||||
34,887274,errors:,2.38,63.30,3.64
|
||||
35,1018333,errors:,1.45,38.02,1.29
|
||||
36,809203,errors:,2.66,229.25,3.51
|
||||
37,1109817,3699.39,1.48,25.94,1.17
|
||||
38,1128419,errors:,1.27,24.27,1.09
|
||||
39,1169809,3899.36,1.44,23.55,1.15
|
||||
40,758943,errors:,3.08,55.78,3.64
|
||||
41,971669,errors:,2.02,63.10,3.14
|
||||
42,1120557,errors:,1.99,59.04,3.20
|
||||
43,1073221,errors:,2.55,68.48,3.99
|
||||
44,1108674,errors:,2.19,59.17,3.47
|
||||
45,1107577,errors:,1.92,75.39,2.92
|
||||
46,1020400,errors:,2.76,74.82,4.07
|
||||
47,1205310,errors:,2.44,76.22,3.77
|
||||
48,1097203,errors:,1.71,63.36,2.49
|
||||
49,1190790,errors:,2.54,68.93,3.95
|
||||
50,1154937,errors:,2.71,73.34,3.99
|
||||
51,1152226,errors:,1.86,68.10,2.71
|
||||
52,1139356,errors:,2.49,64.61,3.77
|
|
2
BENCHMARKING/RESULTS/web_cont_benchmark.csv
Normal file
@ -0,0 +1,2 @@
|
||||
TEST_RUN,QUERIES_SENT,QUERIES_PER_SECOND,AVG_LATENCY_MILLISECONDS,MAX_LATENCY_MILLISECONDS,LATENCY_STD_DEV_PERCENT
|
||||
1,0,errors:,-,0.00,-
|
|
37
BENCHMARKING/RESULTS/web_unik_benchmark.csv
Normal file
@ -0,0 +1,37 @@
|
||||
TEST_RUN,QUERIES_SENT,QUERIES_PER_SECOND,AVG_LATENCY_MILLISECONDS,MAX_LATENCY_MILLISECONDS,LATENCY_STD_DEV_PERCENT
|
||||
1,30004,100.01,3.65,18.64,2.13
|
||||
2,60004,200.01,4.56,22.26,3.23
|
||||
3,90004,300.01,3.08,217.60,3.28
|
||||
4,120004,400.01,4.33,136.96,4.11
|
||||
5,150004,500.01,4.30,95.36,3.54
|
||||
6,180004,600.01,3.24,50.69,2.03
|
||||
7,210004,700.01,2.92,26.43,1.83
|
||||
8,240004,800.01,5.75,40.54,5.37
|
||||
9,269992,899.97,4.49,29.44,3.88
|
||||
10,299986,999.94,3.25,39.71,2.00
|
||||
11,329965,1099.86,7.52,37.73,6.28
|
||||
12,359965,1199.87,10.04,41.28,7.78
|
||||
13,389961,1299.87,5.04,38.02,4.26
|
||||
14,419961,1399.87,3.78,37.63,2.89
|
||||
15,449956,1499.84,5.93,36.70,5.12
|
||||
16,479952,1599.84,4.51,1.02,24.24
|
||||
17,509941,1699.80,3.96,37.34,3.19
|
||||
18,539931,1799.77,8.07,40.10,6.09
|
||||
19,569930,1899.75,4.51,51.68,4.00
|
||||
20,599905,1999.61,10.44,43.14,7.12
|
||||
21,629914,2099.71,5.53,43.97,4.45
|
||||
22,659898,2199.67,5.74,44.67,4.24
|
||||
23,689899,2299.66,6.34,49.92,5.65
|
||||
24,719899,2399.65,11.37,54.05,8.06
|
||||
25,749895,2499.63,8.07,54.66,5.78
|
||||
26,779884,2599.59,8.45,50.14,7.29
|
||||
27,809827,2699.31,15.97,59.55,8.63
|
||||
28,734062,2446.83,5.45,37.98,10.68
|
||||
29,869861,2899.54,12.20,58.46,8.84
|
||||
30,784697,2615.19,6.37,38.34,11.19
|
||||
31,818727,2728.72,3.71,35.82,8.43
|
||||
32,632347,2106.63,41.77,1.71,33.16
|
||||
33,674216,2246.32,47.19,1.60,28.58
|
||||
34,606538,2021.69,1.06,2.03,35.14
|
||||
35,719335,2396.51,47.68,1.58,26.97
|
||||
36,590733,1969.06,1.13,2.27,39.42
|
|
36
BENCHMARKING/UNIKERNEL/DNS/CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
|
||||
# IncludeOS install location
|
||||
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
|
||||
set(ENV{INCLUDEOS_PREFIX} /usr/local)
|
||||
endif()
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
|
||||
project (DNS)
|
||||
|
||||
# Human-readable name of your service
|
||||
set(SERVICE_NAME "CETIC DNS Service")
|
||||
|
||||
# Name of your service binary
|
||||
set(BINARY "DNS")
|
||||
|
||||
# Source files to be linked with OS library parts to form bootable image
|
||||
set(SOURCES
|
||||
service.cpp # ...add more here
|
||||
)
|
||||
|
||||
# To add your own include paths:
|
||||
# set(LOCAL_INCLUDES ".")
|
||||
|
||||
# DRIVERS / PLUGINS:
|
||||
|
||||
set(DRIVERS
|
||||
virtionet # Virtio networking
|
||||
# virtioblock # Virtio block device
|
||||
# ... Others from src/drivers
|
||||
)
|
||||
|
||||
set(PLUGINS
|
||||
)
|
||||
|
||||
# include service build script
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
|
7
BENCHMARKING/UNIKERNEL/DNS/cmake_build.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
pushd build
|
||||
cmake ..
|
||||
make
|
||||
popd
|
11
BENCHMARKING/UNIKERNEL/DNS/config.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"net": [
|
||||
{
|
||||
"iface": 0,
|
||||
"config": "static",
|
||||
"address": "192.168.122.100",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "192.168.122.1"
|
||||
}
|
||||
]
|
||||
}
|
262
BENCHMARKING/UNIKERNEL/DNS/service.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
/**
|
||||
* Basic DNS server for the IncludeOS unikernel framework.
|
||||
*
|
||||
* This code uses portions of code created by GitHub user tomasorti for his dns-server project (https://github.com/tomasorti/dns-server)
|
||||
*/
|
||||
|
||||
#include <service>
|
||||
#include <net/inet4>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace net;
|
||||
|
||||
#define SERVER_PORT 53
|
||||
|
||||
static const uint QR_MASK = 0x8000;
|
||||
static const uint OPCODE_MASK = 0x7800;
|
||||
static const uint AA_MASK = 0x0400;
|
||||
static const uint TC_MASK = 0x0200;
|
||||
static const uint RD_MASK = 0x0100;
|
||||
static const uint RA_MASK = 0x8000;
|
||||
static const uint RCODE_MASK = 0x000F;
|
||||
static const uint HDR_OFFSET = 12;
|
||||
static const int BUFFER_SIZE = 1024;
|
||||
|
||||
// for more info on DNS fields, see RFC 1035
|
||||
|
||||
struct queryHeader {
|
||||
uint id; // 16 bit identifier assigned by the program who generated the query
|
||||
uint query; // identifies if message is query (0) or a response (1)
|
||||
uint opcode; // 4 bit field specifying kind of query: standard (0), inverse (1), server status request (2), reserved (3-15)
|
||||
uint aa; // bit indicating if responding server is an authority for the domain name
|
||||
uint truncation; // specifies whether this message was truncated or not
|
||||
uint recursionDesired; // may be set in a query, directs the name server to pursue the query recursively
|
||||
uint recursionAvailable; // set in a response, indicates whether recursive queries are available
|
||||
uint responseCode; // 4 bit response code: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused
|
||||
|
||||
// unsigned 16-bit integers
|
||||
uint questionCount; // number of entries in the question section
|
||||
uint answerCount; // number of resource reconds in the answer section
|
||||
uint nameServerCount; // number of name server resource records in the authority records section
|
||||
uint additionalResourceCount; // number of resource records in the additional records section
|
||||
};
|
||||
|
||||
struct queryQuestion {
|
||||
std::string queryName; // domain name requested
|
||||
uint queryType; // 2 octet code specifying the type of the query
|
||||
uint queryClass; // 2 octet code specifying the class of the query
|
||||
};
|
||||
|
||||
queryHeader pQueryHeader;
|
||||
queryQuestion pQueryQuestion;
|
||||
std::map<std::string,std::vector<int>> resourceRecords;
|
||||
|
||||
uint get16bits(const char*& buffer) {
|
||||
uint value = static_cast<u_char> (buffer[0]);
|
||||
value = value << 8;
|
||||
value += static_cast<u_char> (buffer[1]);
|
||||
buffer += 2;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void put8bits(char*& buffer, uint value) throw () {
|
||||
buffer[0] = (value);
|
||||
buffer += 1;
|
||||
}
|
||||
|
||||
void put16bits(char*& buffer, uint value) throw () {
|
||||
buffer[0] = (value & 0xFF00) >> 8;
|
||||
buffer[1] = value & 0xFF;
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
void put32bits(char*& buffer, ulong value) throw () {
|
||||
buffer[0] = (value & 0xFF000000) >> 24;
|
||||
buffer[1] = (value & 0xFF0000) >> 16;
|
||||
buffer[2] = (value & 0xFF00) >> 16;
|
||||
buffer[3] = (value & 0xFF) >> 16;
|
||||
buffer += 4;
|
||||
}
|
||||
|
||||
queryHeader decodeHeader(const char* data, queryHeader pQueryHeader){
|
||||
pQueryHeader.id = get16bits(data);
|
||||
|
||||
uint fields = get16bits(data);
|
||||
pQueryHeader.query = fields & QR_MASK;
|
||||
pQueryHeader.opcode = fields & OPCODE_MASK;
|
||||
pQueryHeader.aa = fields & AA_MASK;
|
||||
pQueryHeader.truncation = fields & TC_MASK;
|
||||
pQueryHeader.recursionDesired = fields & RD_MASK;
|
||||
pQueryHeader.recursionAvailable = fields & RA_MASK;
|
||||
|
||||
pQueryHeader.questionCount = get16bits(data);
|
||||
pQueryHeader.answerCount = get16bits(data);
|
||||
pQueryHeader.nameServerCount = get16bits(data);
|
||||
pQueryHeader.additionalResourceCount = get16bits(data);
|
||||
return pQueryHeader;
|
||||
}
|
||||
|
||||
queryQuestion decodeQuery(const char*& data, queryQuestion pQueryQuestion){
|
||||
pQueryQuestion.queryName = "";
|
||||
|
||||
int length = *data++;
|
||||
while (length != 0) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = *data++;
|
||||
pQueryQuestion.queryName.append(1, c);
|
||||
}
|
||||
length = *data++;
|
||||
if (length != 0) pQueryQuestion.queryName.append(1,'.');
|
||||
}
|
||||
|
||||
pQueryQuestion.queryType = get16bits(data);
|
||||
pQueryQuestion.queryClass = get16bits(data);
|
||||
return pQueryQuestion;
|
||||
}
|
||||
|
||||
void codeDomain(char*& buffer, const std::string& domain) {
|
||||
int start = 0, end; // indexes
|
||||
while ((end = domain.find('.', start)) != std::string::npos) {
|
||||
*buffer++ = end - start; // label length octet
|
||||
for (int i=start; i<end; i++) {
|
||||
*buffer++ = domain[i]; // label octets
|
||||
}
|
||||
start = end + 1; // Skip '.'
|
||||
}
|
||||
|
||||
*buffer++ = domain.size() - start; // last label length octet
|
||||
for (int i=start; i<domain.size(); i++) {
|
||||
*buffer++ = domain[i]; // last label octets
|
||||
}
|
||||
*buffer++ = 0;
|
||||
}
|
||||
|
||||
|
||||
int processQuery(char* buffer, queryHeader pQueryHeader, queryQuestion pQueryQuestion){
|
||||
|
||||
// search for domain in resourceRecords
|
||||
bool bRRexists = true;
|
||||
std::map<std::string,std::vector<int>>::iterator record = resourceRecords.find(pQueryQuestion.queryName);
|
||||
if (record == resourceRecords.end())
|
||||
bRRexists = false;
|
||||
|
||||
|
||||
char* bufferBegin = buffer;
|
||||
|
||||
// create header
|
||||
put16bits(buffer, pQueryHeader.id);
|
||||
|
||||
int fields = (1 << 15); // Response code
|
||||
fields += (0 << 11); // Opcode
|
||||
fields += (0 << 10); // Authoritative code
|
||||
fields += (0 << 9); // Truncated code
|
||||
fields += (1 << 8); // Recursion desired code
|
||||
fields += (0 << 7); // Recursion available code
|
||||
fields += (0 << 6); // Z reserved code
|
||||
fields += (0 << 5); // Answers authenticated code
|
||||
fields += (0 << 4); // Non-authenticated data code
|
||||
if(bRRexists)
|
||||
fields += 0; // Reply code
|
||||
else
|
||||
fields += 3;
|
||||
put16bits(buffer, fields);
|
||||
|
||||
put16bits(buffer, pQueryHeader.questionCount); // Questions count
|
||||
if(bRRexists)
|
||||
put16bits(buffer, 1); // Answers count
|
||||
else
|
||||
put16bits(buffer, 0);
|
||||
put16bits(buffer, 0); // Authority RRs
|
||||
put16bits(buffer, 0); // Additional RRs
|
||||
|
||||
// create domain query section - copy original question format
|
||||
codeDomain(buffer, pQueryQuestion.queryName);
|
||||
put16bits(buffer, pQueryQuestion.queryType);
|
||||
put16bits(buffer, pQueryQuestion.queryClass);
|
||||
|
||||
// if requested domain exists in resourceRecords, create the answer
|
||||
if(bRRexists){
|
||||
// compression code to pointing to original question - should be offset from ID to domain name (in number of 16bits)
|
||||
put16bits(buffer, 49164);
|
||||
|
||||
put16bits(buffer, pQueryQuestion.queryType);
|
||||
put16bits(buffer, pQueryQuestion.queryClass);
|
||||
put32bits(buffer, 0); // time to live
|
||||
|
||||
put16bits(buffer, 4); // data length (always 4 for IPv4 addresses)
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][0]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][1]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][2]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][3]);
|
||||
}
|
||||
|
||||
int size = buffer - bufferBegin;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
resourceRecords["www.cetic.be"].push_back(10);
|
||||
resourceRecords["www.cetic.be"].push_back(0);
|
||||
resourceRecords["www.cetic.be"].push_back(0);
|
||||
resourceRecords["www.cetic.be"].push_back(5);
|
||||
resourceRecords["cetic.be"].push_back(10);
|
||||
resourceRecords["cetic.be"].push_back(0);
|
||||
resourceRecords["cetic.be"].push_back(0);
|
||||
resourceRecords["cetic.be"].push_back(5);
|
||||
resourceRecords["internship.cetic.be"].push_back(10);
|
||||
resourceRecords["internship.cetic.be"].push_back(0);
|
||||
resourceRecords["internship.cetic.be"].push_back(0);
|
||||
resourceRecords["internship.cetic.be"].push_back(5);
|
||||
|
||||
// get the first network interfaces of the unikernel
|
||||
auto& inet = Inet4::stack<0>();
|
||||
Expects(inet.is_configured());
|
||||
|
||||
printf("Service IP address is %s\n", inet.ip_addr().str().c_str());
|
||||
|
||||
const UDP::port_t port = SERVER_PORT;
|
||||
auto& sock = inet.udp().bind(port);
|
||||
|
||||
sock.on_read(
|
||||
[&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len){
|
||||
|
||||
pQueryHeader = decodeHeader(data, pQueryHeader);
|
||||
data += HDR_OFFSET;
|
||||
pQueryQuestion = decodeQuery(data, pQueryQuestion);
|
||||
|
||||
// debug output
|
||||
printf("####### INCOMMING REQUEST #######\n");
|
||||
printf("Getting UDP data from %s:%d\n", addr.str().c_str(), port);
|
||||
printf("Header:\n");
|
||||
printf("\tID: %u\n",pQueryHeader.id);
|
||||
printf("\tQuery: %u\n", pQueryHeader.query);
|
||||
printf("\topCode: %u\n", pQueryHeader.opcode);
|
||||
printf("\tAA: %u\n", pQueryHeader.aa);
|
||||
printf("\tTruncation: %u\n", pQueryHeader.truncation);
|
||||
printf("\tRecursion Desired: %u\n", pQueryHeader.recursionDesired);
|
||||
printf("\tRecursion Available: %u\n", pQueryHeader.recursionAvailable);
|
||||
printf("\tReponse Code: %u\n", pQueryHeader.responseCode);
|
||||
printf("\tQuestion Count: %u\n", pQueryHeader.questionCount);
|
||||
printf("\tAnswer Count: %u\n", pQueryHeader.answerCount);
|
||||
printf("\tName Server Count: %u\n", pQueryHeader.nameServerCount);
|
||||
printf("\tAdditional Resource Count: %u\n", pQueryHeader.additionalResourceCount);
|
||||
printf("Query:\n");
|
||||
printf("\tQuery name: %s\n", pQueryQuestion.queryName.data());
|
||||
printf("\tQuery Type: %u\n", pQueryQuestion.queryType);
|
||||
printf("\tAdditional Resource Count: %u\n", pQueryQuestion.queryClass);
|
||||
printf("#################################\n");
|
||||
|
||||
// send reply
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
int nbrBytes = processQuery(buffer, pQueryHeader, pQueryQuestion);
|
||||
|
||||
sock.sendto(addr, port, buffer, nbrBytes);
|
||||
});
|
||||
|
||||
INFO("DNS Server", "Listening on port %d\n", port);
|
||||
}
|
6
BENCHMARKING/UNIKERNEL/DNS/vm.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"net" : [
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"},
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"}
|
||||
]
|
||||
}
|
42
BENCHMARKING/UNIKERNEL/WebServer/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
|
||||
set(ENV{INCLUDEOS_PREFIX} /usr/local)
|
||||
endif()
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
|
||||
|
||||
project (WebServer)
|
||||
|
||||
# Human-readable name of your service
|
||||
set(SERVICE_NAME "CETIC Unikernel Web Server")
|
||||
|
||||
# Name of your service binary
|
||||
set(BINARY "WebServer")
|
||||
|
||||
# Source files to be linked with OS library parts to form bootable image
|
||||
set(SOURCES
|
||||
service.cpp # ...add more here
|
||||
)
|
||||
|
||||
# To add your own include paths:
|
||||
# set(LOCAL_INCLUDES ".")
|
||||
|
||||
# DRIVERS / PLUGINS:
|
||||
set(DRIVERS
|
||||
virtionet # Virtio networking
|
||||
)
|
||||
|
||||
set(PLUGINS
|
||||
autoconf
|
||||
)
|
||||
|
||||
# STATIC LIBRARIES:
|
||||
set(LIBRARIES
|
||||
# path to full library
|
||||
)
|
||||
|
||||
|
||||
# include service build script
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
|
||||
|
||||
# Create in-memory filesystem from folder
|
||||
diskbuilder(disk)
|
7
BENCHMARKING/UNIKERNEL/WebServer/cmake_build.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
pushd build
|
||||
cmake ..
|
||||
make
|
||||
popd
|
13
BENCHMARKING/UNIKERNEL/WebServer/config.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"net": [
|
||||
{
|
||||
"iface": 0,
|
||||
"config": "static",
|
||||
"address": "192.168.122.5",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "192.168.122.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
15
BENCHMARKING/UNIKERNEL/WebServer/disk/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>CETIC Internship Unikernel Web Page</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu:500,300" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="font-family: Arial, sans-serif">
|
||||
CETIC Internship Unikernel Web Page
|
||||
</h1>
|
||||
<hr />
|
||||
<p>This is the first web server spawn from a unikernel during the CETIC Intership 2017-18</p>
|
||||
</body>
|
||||
</html>
|
47
BENCHMARKING/UNIKERNEL/WebServer/service.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This code is adapted from the IncludeOS Acorn web server example.
|
||||
*/
|
||||
|
||||
#include <service>
|
||||
#include <net/inet4>
|
||||
#include <net/http/server.hpp>
|
||||
#include <memdisk>
|
||||
std::unique_ptr<http::Server> server;
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
// Retreive the stack (configured from outside)
|
||||
auto& inet = net::Inet4::stack<0>();
|
||||
Expects(inet.is_configured());
|
||||
|
||||
// Init the memdisk
|
||||
auto& disk = fs::memdisk();
|
||||
disk.init_fs([] (auto err, auto&) {
|
||||
Expects(not err);
|
||||
});
|
||||
// Retreive the HTML page from the disk
|
||||
auto file = disk.fs().read_file("/index.html");
|
||||
Expects(file.is_valid());
|
||||
net::tcp::buffer_t html(
|
||||
new std::vector<uint8_t> (file.data(), file.data() + file.size()));
|
||||
|
||||
// Create a HTTP Server and setup request handling
|
||||
server = std::make_unique<http::Server>(inet.tcp());
|
||||
server->on_request([html] (auto req, auto rw)
|
||||
{
|
||||
// We only support get
|
||||
if(req->method() != http::GET) {
|
||||
rw->write_header(http::Not_Found);
|
||||
return;
|
||||
}
|
||||
// Serve HTML on /
|
||||
if(req->uri() == "/") {
|
||||
rw->write(html);
|
||||
} else {
|
||||
rw->write_header(http::Not_Found);
|
||||
}
|
||||
});
|
||||
|
||||
// Start listening on port 80
|
||||
server->listen(80);
|
||||
}
|
38
BENCHMARKING/bench_container_dns.sh
Normal file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
SRC_DIR=$HOME/unikernels
|
||||
CONTAINERS=$SRC_DIR/SOURCE/CONTAINER
|
||||
|
||||
#IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n')
|
||||
IP=10.65.0.101
|
||||
PORT=53
|
||||
|
||||
source $SRC_DIR/BENCHMARKING/bench_unikernel_cleanup.sh
|
||||
|
||||
# build Docker containers
|
||||
# 1 - compiler docker
|
||||
pushd $CONTAINERS &&
|
||||
docker build -t cetic/compiler . &&
|
||||
popd &&
|
||||
|
||||
# 2 - individual dockers
|
||||
pushd $CONTAINERS/DNS &&
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp &&
|
||||
docker build -t cetic/dns . &&
|
||||
popd &&
|
||||
|
||||
# stopping all VMs and containers
|
||||
docker stop $(docker ps -a -q)
|
||||
virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do
|
||||
virsh destroy $DOMAIN
|
||||
sleep 3
|
||||
done
|
||||
|
||||
# launch docker containers
|
||||
docker run --rm --cpus 1 -m 128m -d -p $IP:$PORT:$PORT/udp --name DNSBench cetic/dns &&
|
||||
|
||||
echo "#############################################################################" &&
|
||||
echo "### ###" &&
|
||||
echo "### Container DNS Server ready for benchmark. ###" &&
|
||||
echo "### $IP:$PORT ###" &&
|
||||
echo "### ###" &&
|
||||
echo "#############################################################################"
|
38
BENCHMARKING/bench_container_web.sh
Normal file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
SRC_DIR=$HOME/unikernels
|
||||
CONTAINERS=$SRC_DIR/SOURCE/CONTAINER
|
||||
|
||||
#IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n')
|
||||
IP=10.65.0.101
|
||||
PORT=80
|
||||
|
||||
source $SRC_DIR/BENCHMARKING/bench_unikernel_cleanup.sh
|
||||
|
||||
# build Docker containers
|
||||
# 1 - compiler docker
|
||||
pushd $CONTAINERS &&
|
||||
docker build -t cetic/compiler . &&
|
||||
popd &&
|
||||
|
||||
# 2 - individual dockers
|
||||
pushd $CONTAINERS/WebServer &&
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp &&
|
||||
docker build -t cetic/webserver . &&
|
||||
popd &&
|
||||
|
||||
# stopping all VMs and containers
|
||||
docker stop $(docker ps -a -q)
|
||||
virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do
|
||||
virsh destroy $DOMAIN
|
||||
sleep 3
|
||||
done
|
||||
|
||||
# launch docker containers
|
||||
docker run --rm --cpus 1 -m 128m -d -p $IP:$PORT:$PORT --name WebServerBench cetic/webserver &&
|
||||
|
||||
echo "#############################################################################" &&
|
||||
echo "### ###" &&
|
||||
echo "### Container Web Server ready for benchmark. ###" &&
|
||||
echo "### $IP:$PORT ###" &&
|
||||
echo "### ###" &&
|
||||
echo "#############################################################################"
|
13
BENCHMARKING/bench_unikernel_cleanup.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
WEB_IP=192.168.122.5
|
||||
DNS_IP=192.168.122.100
|
||||
WEB_PORT=80
|
||||
DNS_PORT=53
|
||||
BRIDGE_INTERFACE=virbr0
|
||||
|
||||
sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $DNS_IP -j ACCEPT
|
||||
sudo iptables -t nat -D PREROUTING -p udp --dport $DNS_PORT -j DNAT --to $DNS_IP:$DNS_PORT
|
||||
|
||||
sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $WEB_IP -j ACCEPT
|
||||
sudo iptables -t nat -D PREROUTING -p tcp --dport $WEB_PORT -j DNAT --to $WEB_IP:$WEB_PORT
|
55
BENCHMARKING/bench_unikernel_dns.sh
Normal file
@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
SRC_DIR=$HOME/unikernels/BENCHMARKING
|
||||
UNIKERNELS=$SRC_DIR/UNIKERNEL
|
||||
|
||||
HOST_IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n')
|
||||
GUEST_IP=192.168.122.100
|
||||
GUEST_PORT=53
|
||||
HOST_PORT=53
|
||||
BRIDGE_INTERFACE=virbr0
|
||||
|
||||
#write correct JSON file
|
||||
pushd $UNIKERNELS/DNS &&
|
||||
jq -n --arg IP_ADDRESS "$GUEST_IP" '{"net": [{"netmask": "255.255.255.0", "config": "static", "iface": 0, "gateway": "192.168.122.1", "address": $IP_ADDRESS}]}' > config.json &&
|
||||
# build unikernels
|
||||
sudo rm -rf build &&
|
||||
mkdir -p build &&
|
||||
pushd build &&
|
||||
cmake .. &&
|
||||
sudo make &&
|
||||
popd &&
|
||||
popd &&
|
||||
|
||||
# shuting down all VMs
|
||||
docker stop $(docker ps -a -q)
|
||||
virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do
|
||||
virsh destroy $DOMAIN
|
||||
sleep 3
|
||||
if [ "$DOMAIN" == "DNSBench" ]
|
||||
then
|
||||
virsh undefine $DOMAIN
|
||||
fi
|
||||
done
|
||||
virsh undefine DNSBench
|
||||
|
||||
# launch unikernels in QEMU (+serial output to files)
|
||||
virt-install \
|
||||
--virt-type qemu --name DNSBench \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk $UNIKERNELS/DNS/build/DNS.img \
|
||||
--serial file,path=/tmp/dns-benchmark.log \
|
||||
--network network=default,model=virtio \
|
||||
--check path_in_use=off \
|
||||
--noautoconsole &&
|
||||
|
||||
# enable port-forwarding through iptables
|
||||
source $SRC_DIR/bench_unikernel_cleanup.sh
|
||||
sudo iptables -I FORWARD -o $BRIDGE_INTERFACE -d $GUEST_IP -j ACCEPT &&
|
||||
sudo iptables -t nat -I PREROUTING -p udp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT &&
|
||||
|
||||
echo "#############################################################################" &&
|
||||
echo "### ###" &&
|
||||
echo "### Unikernel DNS Server ready for benchmark. ###" &&
|
||||
echo "### $HOST_IP:$HOST_PORT ###" &&
|
||||
echo "### ###" &&
|
||||
echo "#############################################################################"
|
52
BENCHMARKING/bench_unikernel_web.sh
Normal file
@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
SRC_DIR=$HOME/unikernels/BENCHMARKING
|
||||
UNIKERNELS=$SRC_DIR/UNIKERNEL
|
||||
|
||||
HOST_IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n')
|
||||
GUEST_IP=192.168.122.5
|
||||
GUEST_PORT=80
|
||||
HOST_PORT=80
|
||||
BRIDGE_INTERFACE=virbr0
|
||||
|
||||
# writing correct JSON file
|
||||
pushd $UNIKERNELS/DNS &&
|
||||
jq -n --arg IP_ADDRESS "$GUEST_IP" '{"net": [{"netmask": "255.255.255.0", "config": "static", "iface": 0, "gateway": "192.168.122.1", "address": $IP_ADDRESS}]}' > config.json &&
|
||||
# build unikernels
|
||||
sudo rm -rf build &&
|
||||
mkdir -p build &&
|
||||
pushd build &&
|
||||
cmake .. &&
|
||||
sudo make &&
|
||||
popd &&
|
||||
popd &&
|
||||
|
||||
# shuting down all VMs
|
||||
docker stop $(docker ps -a -q)
|
||||
virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do
|
||||
virsh destroy $DOMAIN
|
||||
sleep 3
|
||||
done
|
||||
virsh undefine WebServerBench
|
||||
|
||||
# launch unikernels in QEMU (+serial output to files)
|
||||
virt-install \
|
||||
--virt-type qemu --name WebServerBench \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk $UNIKERNELS/WebServer/build/WebServer.img \
|
||||
--serial file,path=/tmp/web-benchmark.log \
|
||||
--network network=default,model=virtio \
|
||||
--check path_in_use=off \
|
||||
--noautoconsole &&
|
||||
|
||||
# enable port-forwarding through iptables
|
||||
source $SRC_DIR/bench_unikernel_cleanup.sh
|
||||
sudo iptables -I FORWARD -o $BRIDGE_INTERFACE -d $GUEST_IP -j ACCEPT &&
|
||||
sudo iptables -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT &&
|
||||
|
||||
echo "#############################################################################" &&
|
||||
echo "### ###" &&
|
||||
echo "### Unikernel Web Server ready for benchmark. ###" &&
|
||||
echo "### $HOST_IP:$HOST_PORT ###" &&
|
||||
echo "### ###" &&
|
||||
echo "#############################################################################"
|
||||
|
30
BENCHMARKING/cleanup_all.sh
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# REMOVING IP TABLES RULES FOR UNIKERNEL BENCHMARKING
|
||||
WEB_IP=192.168.122.5
|
||||
DNS_IP=192.168.122.10
|
||||
WEB_PORT=80
|
||||
DNS_PORT=53
|
||||
BRIDGE_INTERFACE=virbr0
|
||||
|
||||
sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $DNS_IP -j ACCEPT
|
||||
sudo iptables -t nat -D PREROUTING -p udp --dport $DNS_PORT -j DNAT --to $DNS_IP:$DNS_PORT
|
||||
sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $WEB_IP -j ACCEPT
|
||||
sudo iptables -t nat -D PREROUTING -p tcp --dport $WEB_PORT -j DNAT --to $WEB_IP:$WEB_PORT
|
||||
|
||||
echo "This will stop and delete all VMs and Containers !"
|
||||
read -p "Are you sure ? [Y|N] " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
# STOPPING AND DELETING ALL CONTAINERS
|
||||
docker stop $(docker ps -a -q)
|
||||
docker rm $(docker ps -a -q)
|
||||
virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do
|
||||
virsh destroy $DOMAIN
|
||||
done
|
||||
virsh list --all | grep "shut off" | awk '{ print $2}' | while read DOMAIN; do
|
||||
virsh undefine $DOMAIN
|
||||
done
|
||||
fi
|
||||
|
67
BENCHMARKING/dns_cont_benchmark.py
Normal file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import os.path
|
||||
import csv
|
||||
import time
|
||||
|
||||
RUN=1
|
||||
TIME=300
|
||||
CLIENTS=100
|
||||
THREADS=4
|
||||
QPS=100
|
||||
QPS_INCREMENT=100
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 dns_cont_benchmark.py [server_ip_address]")
|
||||
sys.exit(1)
|
||||
|
||||
SVR_IP=sys.argv[1]
|
||||
|
||||
if shutil.which("dnsperf") is None:
|
||||
print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.")
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile("dns_cont_benchmark.csv") is not True:
|
||||
subprocess.run("touch dns_cont_benchmark.csv", stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
with open("dns_cont_benchmark.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_COMPLETED", "QUERIES_LOST", "QUERIES_PER_SECOND", "AVG_LATENCY_SECONDS", "MIN", "MAX", "LATENCY_STD_DEV_SECONDS"])
|
||||
|
||||
while True:
|
||||
print("########## LAUNCHING TEST " + str(RUN) + " ##########")
|
||||
print("Queries per seconds: " + str(QPS)+ "\n")
|
||||
# launch the dnsperf command
|
||||
result = subprocess.run("dnsperf -s " + SVR_IP + " -d queryfile-example-current -l " + str(TIME) + " -T " + str(THREADS) + " -c " + str(CLIENTS) + " -Q " + str(QPS), stdout=subprocess.PIPE, shell=True)
|
||||
#print(result.stdout.decode('utf-8'))
|
||||
|
||||
# convert output and store it in the csv file
|
||||
list = result.stdout.decode("utf-8").split('\n')
|
||||
for index in range(len(list)):
|
||||
if list[index].startswith(" Queries sent:"):
|
||||
queriesSent=list[index].split()[2]
|
||||
queriesCompleted=list[index+1].split()[2]
|
||||
queriesLost=list[index+2].split()[2]
|
||||
queriesPerSecond=list[index+7].split()[3]
|
||||
avgLatency=list[index+9].split()[3]
|
||||
latencyMin=list[index+9].split()[5].replace(",", "")
|
||||
latencyMax=list[index+9].split()[7].replace(")", "")
|
||||
latencyStdDev=list[index+10].split()[3]
|
||||
#print("TEST_RUN, QUERIES_SENT, QUERIES_COMPLETED, QUERIES_LOST, QUERIES_PER_SECOND, AVG_LATENCY_SECONDS, MIN, MAX, LATENCY_STD_DEV_SECONDS")
|
||||
print("Queries sent:\t\t" + queriesSent + "\nQueries completed:\t" + queriesCompleted + "\nQueries Lost:\t\t" + queriesLost + \
|
||||
"\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "\nMinimum latency:\t" + latencyMin + \
|
||||
"\nMax latency:\t\t" + latencyMax + "\nLatency Std Dev:\t" + latencyStdDev)
|
||||
with open("dns_cont_benchmark.csv", "a") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([RUN, queriesSent, queriesCompleted, queriesLost, queriesPerSecond, avgLatency, latencyMin, latencyMax, latencyStdDev])
|
||||
break
|
||||
|
||||
print("########## TEST " + str(RUN) + " COMPLETE ##########\n")
|
||||
# increase the TEST_RUN value and increment the number of queries per second
|
||||
RUN=RUN+1
|
||||
QPS=QPS+QPS_INCREMENT
|
||||
# sleep for 30 seconds between tests
|
||||
time.sleep(30)
|
67
BENCHMARKING/dns_unik_benchmark.py
Normal file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import os.path
|
||||
import csv
|
||||
import time
|
||||
|
||||
RUN=1
|
||||
TIME=300
|
||||
CLIENTS=100
|
||||
THREADS=4
|
||||
QPS=100
|
||||
QPS_INCREMENT=100
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 dns_unik_benchmark.py [server_ip_address]")
|
||||
sys.exit(1)
|
||||
|
||||
SVR_IP=sys.argv[1]
|
||||
|
||||
if shutil.which("dnsperf") is None:
|
||||
print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.")
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile("dns_unik_benchmark.csv") is not True:
|
||||
subprocess.run("touch dns_unik_benchmark.csv", stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
with open("dns_unik_benchmark.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_COMPLETED", "QUERIES_LOST", "QUERIES_PER_SECOND", "AVG_LATENCY_SECONDS", "MIN", "MAX", "LATENCY_STD_DEV_SECONDS"])
|
||||
|
||||
while True:
|
||||
print("########## LAUNCHING TEST " + str(RUN) + " ##########")
|
||||
print("Queries per seconds: " + str(QPS)+ "\n")
|
||||
# launch the dnsperf command
|
||||
result = subprocess.run("dnsperf -s " + SVR_IP + " -d queryfile-example-current -l " + str(TIME) + " -T " + str(THREADS) + " -c " + str(CLIENTS) + " -Q " + str(QPS), stdout=subprocess.PIPE, shell=True)
|
||||
#print(result.stdout.decode('utf-8'))
|
||||
|
||||
# convert output and store it in the csv file
|
||||
list = result.stdout.decode("utf-8").split('\n')
|
||||
for index in range(len(list)):
|
||||
if list[index].startswith(" Queries sent:"):
|
||||
queriesSent=list[index].split()[2]
|
||||
queriesCompleted=list[index+1].split()[2]
|
||||
queriesLost=list[index+2].split()[2]
|
||||
queriesPerSecond=list[index+7].split()[3]
|
||||
avgLatency=list[index+9].split()[3]
|
||||
latencyMin=list[index+9].split()[5].replace(",", "")
|
||||
latencyMax=list[index+9].split()[7].replace(")", "")
|
||||
latencyStdDev=list[index+10].split()[3]
|
||||
#print("TEST_RUN, QUERIES_SENT, QUERIES_COMPLETED, QUERIES_LOST, QUERIES_PER_SECOND, AVG_LATENCY_SECONDS, MIN, MAX, LATENCY_STD_DEV_SECONDS")
|
||||
print("Queries sent:\t\t" + queriesSent + "\nQueries completed:\t" + queriesCompleted + "\nQueries Lost:\t\t" + queriesLost + \
|
||||
"\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "\nMinimum latency:\t" + latencyMin + \
|
||||
"\nMax latency:\t\t" + latencyMax + "\nLatency Std Dev:\t" + latencyStdDev)
|
||||
with open("dns_unik_benchmark.csv", "a") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([RUN, queriesSent, queriesCompleted, queriesLost, queriesPerSecond, avgLatency, latencyMin, latencyMax, latencyStdDev])
|
||||
break
|
||||
|
||||
print("########## TEST " + str(RUN) + " COMPLETE ##########\n")
|
||||
# increase the TEST_RUN value and increment the number of queries per second
|
||||
RUN=RUN+1
|
||||
QPS=QPS+QPS_INCREMENT
|
||||
# sleep for 30 seconds between tests
|
||||
time.sleep(30)
|
24
BENCHMARKING/install_bench_tools.sh
Normal file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
SRC_DIR=$HOME/unikernels/BENCHMARKING
|
||||
|
||||
# DNSPerf
|
||||
sudo apt-get install -y libbind-dev libkrb5-dev libssl-dev libcap-dev libxml2-dev libgeoip-dev bind9utils make &&
|
||||
wget ftp://ftp.nominum.com/pub/nominum/dnsperf/2.1.0.0/dnsperf-src-2.1.0.0-1.tar.gz &&
|
||||
tar xzvf dnsperf-src-2.1.0.0-1.tar.gz &&
|
||||
pushd dnsperf-src-2.1.0.0-1 &&
|
||||
./configure &&
|
||||
make &&
|
||||
sudo make install &&
|
||||
popd &&
|
||||
wget ftp://ftp.nominum.com/pub/nominum/dnsperf/data/queryfile-example-current.gz &&
|
||||
gunzip queryfile-example-current.gz &&
|
||||
#Usage: dnsperf -s 10.0.0.100 -d queryfile-example-current -l 60 -c 1 -Q 10
|
||||
|
||||
#wrk2 install
|
||||
git clone https://github.com/giltene/wrk2 &&
|
||||
pushd wrk2 &&
|
||||
sudo make &&
|
||||
sudo cp wrk /usr/local/bin/wrk2 &&
|
||||
popd
|
||||
#Usage: wrk2 -d 5m -R 100 http://10.0.0.5/
|
94
BENCHMARKING/startup_cont_benchmark.py
Normal file
@ -0,0 +1,94 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import subprocess
|
||||
import os.path
|
||||
import csv
|
||||
import json
|
||||
import time
|
||||
import _thread
|
||||
import os
|
||||
import datetime as datetime
|
||||
import random
|
||||
|
||||
BENCHMARK_TIME_SECONDS=60*20
|
||||
MAX_NBR_VMS=150
|
||||
NBR_VMS_INCREMENT=10
|
||||
GUESTS=dict()
|
||||
NBR_VMS=0
|
||||
|
||||
def run_cmd(COMMAND):
|
||||
return subprocess.run(COMMAND, stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
def timeGuestStart(GUEST):
|
||||
response = 1
|
||||
startTime=datetime.datetime.now()
|
||||
while response is not 0:
|
||||
response = os.system("ping -c 1 " + GUESTS[GUEST] + "> /dev/null 2>&1")
|
||||
endTime=datetime.datetime.now()
|
||||
bootTime=(endTime-startTime).microseconds
|
||||
with open("startup_cont_benchmark.csv", "a") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([NBR_VMS, GUEST, (bootTime/1000000)])
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("Application Startup Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 startup_cont_benchmark.py [nbr of VMs]")
|
||||
sys.exit(1)
|
||||
|
||||
NBR_VMS=int(sys.argv[1])
|
||||
|
||||
if os.path.isfile("startup_cont_benchmark.csv") is not True:
|
||||
subprocess.run("touch startup_cont_benchmark.csv", stdout=subprocess.PIPE, shell=True)
|
||||
with open("startup_cont_benchmark.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(["NBR_OF_GUESTS", "GUEST_STOPPED", "STARTUP_TIME_SECONDS"])
|
||||
|
||||
while NBR_VMS < MAX_NBR_VMS:
|
||||
print("### STOPPING PREVIOUS VMS")
|
||||
# stop all running VMs
|
||||
run_cmd("docker stop $(docker ps -a -q) 2> /dev/null")
|
||||
run_cmd("virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do virsh destroy $DOMAIN; sleep 3; virsh undefine $DOMAIN; done")
|
||||
run_cmd("docker ps -a -q | while read DOMAIN; do docker rm $DOMAIN; done")
|
||||
|
||||
# create table of guest VMs
|
||||
GUESTS.clear()
|
||||
i = 10
|
||||
for x in range(int(NBR_VMS)):
|
||||
GUESTS[("VM_"+str(x))] = ("172.18.0." + str(i))
|
||||
i = i+1
|
||||
|
||||
print("### BUILDING CONTAINERS")
|
||||
run_cmd("cd ../SOURCE/CONTAINER && docker build -t cetic/compiler .")
|
||||
run_cmd("cd ../SOURCE/CONTAINER/DNS &&\
|
||||
docker run --rm -it -v $PWD:/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp &&\
|
||||
docker build -t cetic/dns .")
|
||||
run_cmd("docker network create --subnet=172.18.0.0/16 --driver=bridge bench_net 2> /dev/null")
|
||||
|
||||
print("### LAUNCHING CONTAINERS")
|
||||
# create and launch each VM
|
||||
for key, value in GUESTS.items():
|
||||
# for each entry in GUESTS build the unikernel and move the img to another folder
|
||||
|
||||
run_cmd("docker run --cpus 1 -m 128m -d --ip " + value + " --network=bench_net --name " + key + " cetic/dns 2> /dev/null")
|
||||
|
||||
print("### LAUNCHING BENCHMARK FOR " + str(BENCHMARK_TIME_SECONDS) + " SECONDS")
|
||||
|
||||
timeout=time.time() + BENCHMARK_TIME_SECONDS
|
||||
while time.time() <= timeout:
|
||||
# stop a VM
|
||||
RANDOM_GUEST="VM_"+str(random.randint(0, (int(NBR_VMS)-1)))
|
||||
run_cmd("docker stop " + RANDOM_GUEST)
|
||||
print(RANDOM_GUEST + " shut down")
|
||||
# launch a thread to start a VM
|
||||
_thread.start_new_thread(run_cmd, ("docker start " + RANDOM_GUEST, ))
|
||||
# launch another thread to time boot time
|
||||
_thread.start_new_thread(timeGuestStart, (RANDOM_GUEST, ))
|
||||
print(RANDOM_GUEST + " started...")
|
||||
time.sleep(5)
|
||||
|
||||
#increment number of VMs for next test
|
||||
NBR_VMS=NBR_VMS+NBR_VMS_INCREMENT
|
||||
|
||||
run_cmd("docker stop $(docker ps -a -q) 2> /dev/null")
|
||||
|
||||
|
118
BENCHMARKING/startup_unik_benchmark.py
Normal file
@ -0,0 +1,118 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import subprocess
|
||||
import os.path
|
||||
import csv
|
||||
import json
|
||||
import time
|
||||
import _thread
|
||||
import os
|
||||
import datetime as datetime
|
||||
import random
|
||||
|
||||
BENCHMARK_TIME_SECONDS=60*20
|
||||
MAX_NBR_VMS=150
|
||||
NBR_VMS_INCREMENT=10
|
||||
GUESTS=dict()
|
||||
NBR_VMS=0
|
||||
|
||||
def run_cmd(COMMAND):
|
||||
return subprocess.run(COMMAND, stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
def timeGuestStart(GUEST):
|
||||
response = 1
|
||||
startTime=datetime.datetime.now()
|
||||
while response is not 0:
|
||||
response = os.system("ping -c 1 " + GUESTS[GUEST] + "> /dev/null 2>&1")
|
||||
endTime=datetime.datetime.now()
|
||||
bootTime=(endTime-startTime).microseconds
|
||||
with open("startup_unik_benchmark.csv", "a") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([NBR_VMS, GUEST, (bootTime/1000000)])
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("Application Startup Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 startup_unik_benchmark.py [nbr of VMs]")
|
||||
sys.exit(1)
|
||||
|
||||
NBR_VMS=int(sys.argv[1])
|
||||
|
||||
if os.path.isfile("startup_unik_benchmark.csv") is not True:
|
||||
subprocess.run("touch startup_unik_benchmark.csv", stdout=subprocess.PIPE, shell=True)
|
||||
with open("startup_unik_benchmark.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(["NBR_OF_GUESTS", "GUEST_STOPPED", "STARTUP_TIME_SECONDS"])
|
||||
|
||||
|
||||
while NBR_VMS < MAX_NBR_VMS:
|
||||
print("### STOPPING PREVIOUS VMS")
|
||||
# stop all running VMs
|
||||
run_cmd("docker stop $(docker ps -a -q) 2> /dev/null")
|
||||
run_cmd("virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do virsh destroy $DOMAIN; sleep 3; done")
|
||||
run_cmd("virsh list --all | grep VM_ | awk '{ print $2}' | while read DOMAIN; do virsh undefine $DOMAIN; sleep 3; done")
|
||||
|
||||
# create table of guest VMs
|
||||
GUESTS.clear()
|
||||
i = 10
|
||||
for x in range(int(NBR_VMS)):
|
||||
GUESTS[("VM_"+str(x))] = ("192.168.122." + str(i))
|
||||
i = i+1
|
||||
#print(GUESTS)
|
||||
|
||||
run_cmd("sudo rm -rf GUESTS; mkdir GUESTS")
|
||||
# create and launch each VM
|
||||
print("### BUILDING UNIKERNEL IMAGES")
|
||||
for key, value in GUESTS.items():
|
||||
# modify config.json with the IP address
|
||||
data = {}
|
||||
data["net"] = []
|
||||
data["net"].append({
|
||||
"iface": 0,
|
||||
"config": "static",
|
||||
"address": value ,
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "192.168.122.1"
|
||||
})
|
||||
with open("UNIKERNEL/DNS/config.json", "w") as outfile:
|
||||
json.dump(data, outfile)
|
||||
|
||||
# for each entry in GUESTS build the unikernel and move the img to another folder
|
||||
run_cmd("cd UNIKERNEL/DNS && sudo rm -rf build && mkdir -p build && cd build && cmake .. && sudo make 2> /dev/null")
|
||||
run_cmd(("sudo mv UNIKERNEL/DNS/build/DNS.img GUESTS/" + key + ".img"))
|
||||
|
||||
run_cmd(("virt-install \
|
||||
--virt-type qemu --name " + key + " \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk GUESTS/" + key +".img \
|
||||
--serial file,path=/tmp/" + key + ".log \
|
||||
--network network=default,model=virtio \
|
||||
--check path_in_use=off \
|
||||
--noautoconsole"))
|
||||
print(" - " + key + " built")
|
||||
|
||||
print("### LAUNCHING BENCHMARK FOR " + str(BENCHMARK_TIME_SECONDS) + " SECONDS")
|
||||
|
||||
timeout = time.time() + BENCHMARK_TIME_SECONDS
|
||||
while time.time() <= timeout:
|
||||
# TODO loop for a predetermined number of time
|
||||
# TODO stop a random VM, restart it, time its boot time
|
||||
# stop a VM
|
||||
RANDOM_GUEST="VM_"+str(random.randint(0, (int(NBR_VMS)-1)))
|
||||
run_cmd("virsh destroy " + RANDOM_GUEST)
|
||||
print(RANDOM_GUEST + " shut down")
|
||||
# launch a thread to start a VM
|
||||
_thread.start_new_thread(run_cmd, ("virsh start " + RANDOM_GUEST, ))
|
||||
# launch another thread to time boot time
|
||||
_thread.start_new_thread(timeGuestStart, (RANDOM_GUEST, ))
|
||||
print(RANDOM_GUEST + " started...")
|
||||
time.sleep(5)
|
||||
|
||||
#increment number of VMs for next test
|
||||
NBR_VMS=NBR_VMS+NBR_VMS_INCREMENT
|
||||
|
||||
# cleanup test bed
|
||||
run_cmd("virsh list --all | grep VM_ | awk '{ print $2}' | while read DOMAIN; do virsh destroy $DOMAIN; sleep 3; virsh undefine $DOMAIN; done")
|
||||
run_cmd("sudo rm -rf GUESTS")
|
||||
|
||||
|
||||
|
64
BENCHMARKING/web_cont_benchmark.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import os.path
|
||||
import csv
|
||||
import time
|
||||
import string
|
||||
|
||||
RUN=1
|
||||
TIME=300
|
||||
CONNECTIONS=100
|
||||
THREADS=4
|
||||
QPS=100
|
||||
QPS_INCREMENT=100
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 web_cont_benchmark.py [server_ip_address]")
|
||||
sys.exit(1)
|
||||
|
||||
SVR_IP=sys.argv[1]
|
||||
|
||||
if shutil.which("dnsperf") is None:
|
||||
print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.")
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile("web_cont_benchmark.csv") is not True:
|
||||
subprocess.run("touch web_cont_benchmark.csv", stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
with open("web_cont_benchmark.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_PER_SECOND", "AVG_LATENCY_MILLISECONDS", "MAX_LATENCY_MILLISECONDS", "LATENCY_STD_DEV_PERCENT"])
|
||||
|
||||
while True:
|
||||
print("########## LAUNCHING TEST " + str(RUN) + " ##########")
|
||||
print("Queries per seconds: " + str(QPS))
|
||||
# launch the dnsperf command
|
||||
result = subprocess.run("wrk2 -t " + str(THREADS) + " -d " + str(TIME) + "s -c " + str(CONNECTIONS) + " -R " + str(QPS) + " http://" + SVR_IP + "/", stdout=subprocess.PIPE, shell=True)
|
||||
#print(result.stdout.decode('utf-8'))
|
||||
|
||||
# convert output and store it in the csv file
|
||||
list = result.stdout.decode("utf-8").split('\n')
|
||||
for index in range(len(list)):
|
||||
if list[index].startswith(" Latency"):
|
||||
avgLatency=list[index].split()[1].strip(string.ascii_letters)
|
||||
latencyMax=list[index].split()[3].strip(string.ascii_letters)
|
||||
latencyStdDev=list[index].split()[2].strip(string.ascii_letters)
|
||||
queriesSent=list[index+2].split()[0]
|
||||
queriesPerSecond=list[index+3].split()[1]
|
||||
|
||||
print("Queries sent:\t\t" + queriesSent + "\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "ms" + \
|
||||
"\nMax latency:\t\t" + latencyMax + "ms" + "\nLatency Std Dev:\t" + latencyStdDev + "ms")
|
||||
with open("web_cont_benchmark.csv", "a") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([RUN, queriesSent, queriesPerSecond, avgLatency, latencyMax, latencyStdDev])
|
||||
break
|
||||
|
||||
print("########## TEST " + str(RUN) + " COMPLETE ##########\n")
|
||||
# increase the TEST_RUN value and increment the number of queries per second
|
||||
RUN=RUN+1
|
||||
QPS=QPS+QPS_INCREMENT
|
||||
# sleep for 30 seconds between tests
|
||||
time.sleep(30)
|
64
BENCHMARKING/web_unik_benchmark.py
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/python3
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
import os.path
|
||||
import csv
|
||||
import time
|
||||
import string
|
||||
|
||||
RUN=1
|
||||
TIME=300
|
||||
CONNECTIONS=100
|
||||
THREADS=4
|
||||
QPS=100
|
||||
QPS_INCREMENT=100
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 web_unik_benchmark.py [server_ip_address]")
|
||||
sys.exit(1)
|
||||
|
||||
SVR_IP=sys.argv[1]
|
||||
|
||||
if shutil.which("dnsperf") is None:
|
||||
print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.")
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isfile("web_unik_benchmark.csv") is not True:
|
||||
subprocess.run("touch web_unik_benchmark.csv", stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
with open("web_unik_benchmark.csv", "w") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_PER_SECOND", "AVG_LATENCY_MILLISECONDS", "MAX_LATENCY_MILLISECONDS", "LATENCY_STD_DEV_PERCENT"])
|
||||
|
||||
while True:
|
||||
print("########## LAUNCHING TEST " + str(RUN) + " ##########")
|
||||
print("Queries per seconds: " + str(QPS))
|
||||
# launch the dnsperf command
|
||||
result = subprocess.run("wrk2 -t " + str(THREADS) + " -d " + str(TIME) + "s -c " + str(CONNECTIONS) + " -R " + str(QPS) + " http://" + SVR_IP + "/", stdout=subprocess.PIPE, shell=True)
|
||||
#print(result.stdout.decode('utf-8'))
|
||||
|
||||
# convert output and store it in the csv file
|
||||
list = result.stdout.decode("utf-8").split('\n')
|
||||
for index in range(len(list)):
|
||||
if list[index].startswith(" Latency"):
|
||||
avgLatency=list[index].split()[1].strip(string.ascii_letters)
|
||||
latencyMax=list[index].split()[3].strip(string.ascii_letters)
|
||||
latencyStdDev=list[index].split()[2].strip(string.ascii_letters)
|
||||
queriesSent=list[index+2].split()[0]
|
||||
queriesPerSecond=list[index+3].split()[1]
|
||||
|
||||
print("Queries sent:\t\t" + queriesSent + "\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "ms" + \
|
||||
"\nMax latency:\t\t" + latencyMax + "ms" + "\nLatency Std Dev:\t" + latencyStdDev + "ms")
|
||||
with open("web_unik_benchmark.csv", "a") as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow([RUN, queriesSent, queriesPerSecond, avgLatency, latencyMax, latencyStdDev])
|
||||
break
|
||||
|
||||
print("########## TEST " + str(RUN) + " COMPLETE ##########\n")
|
||||
# increase the TEST_RUN value and increment the number of queries per second
|
||||
RUN=RUN+1
|
||||
QPS=QPS+QPS_INCREMENT
|
||||
# sleep for 30 seconds between tests
|
||||
time.sleep(30)
|
54
DEPLOYMENT/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Deployment
|
||||
|
||||
This folder contains the files to deploy the proof of concept environment.
|
||||
|
||||
## pre_deployment_installation.sh
|
||||
|
||||
Installs all the required components to launch both the unikernel and the container environment.
|
||||
|
||||
Install includes:
|
||||
* IncludeOS project installation
|
||||
* libvirt for unikernel virtual machines deployment
|
||||
* Docker CE for container deployments
|
||||
|
||||
**NOTE:** installation of the Docker CE adds the current user to the docker group, you must logout/login for the changes to take effect.
|
||||
|
||||
## deploy_unikernels.sh
|
||||
|
||||
This script will deploy the unikernels by taking the following steps:
|
||||
* building the unikernels from the source code (in the SOURCE directory)
|
||||
* create the QEMU networks for the unikernels virtual machine
|
||||
* create and launch the virtual machines in their respective networks
|
||||
|
||||
The networks are created with the following addressing:
|
||||
|
||||
![Proof of concept network addressing scheme](https://git.cetic.be/stages/unikernels/raw/feature/stagelongree2018/MEDIA/unikernel_network.PNG "Proof of concept network addressing scheme")
|
||||
|
||||
| VM | IP Address |
|
||||
| ----------- |-----------------|
|
||||
| Firewall | 192.168.100.254 |
|
||||
| Firewall | 192.168.101.3 |
|
||||
| Router | 192.168.101.2 |
|
||||
| Router | 10.0.0.254 |
|
||||
| Web server | 10.0.0.5 |
|
||||
| DNS server | 10.0.0.100 |
|
||||
|
||||
The current proof of concept environment and is self contained. It is not possible to directly connect the firewall to the external network.
|
||||
It is possible to contact the DNS and the web server through iptables rules (examples in the benchmark launching scripts).
|
||||
|
||||
## deploy_containers.sh
|
||||
|
||||
This script will deploy the containers (using ported code from the unikernel versions) by taking the following steps:
|
||||
* building the compiler image
|
||||
* running the compiler image to cross-compile the application
|
||||
* build the application container using the compiled application program
|
||||
* run the container images built in the previous step
|
||||
|
||||
The container ports are mapped as follows:
|
||||
|
||||
| Container | Host Port | Guest Port |
|
||||
| ----------- | ---------- | ---------- |
|
||||
| Web server | 80/tcp | 80/tcp |
|
||||
| DNS server | 53/udp | 53/udp |
|
||||
|
||||
**NOTE:** due to time constraints during the project, the firewall and router applications were not ported to containers.
|
43
DEPLOYMENT/deploy_containers.sh
Normal file
@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
#NB: due to time constraint, only the DNS and WebServer analogs
|
||||
# have code ported from the Unikernel application.
|
||||
# Additionally the container ports are bound to the host's
|
||||
# IP address for benchmarking.
|
||||
|
||||
SRC_DIR=$HOME/unikernels
|
||||
CONTAINERS=$SRC_DIR/SOURCE/CONTAINER
|
||||
|
||||
# exposes the interface with internet connectivity for benchmarking
|
||||
# if your benchmarking device is on another network, adjust accordingly
|
||||
IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n')
|
||||
DNS_PORT=53
|
||||
WEB_PORT=80
|
||||
|
||||
# build Docker containers
|
||||
# 1 - compiler docker
|
||||
pushd $CONTAINERS &&
|
||||
docker build -t cetic/compiler . &&
|
||||
popd &&
|
||||
|
||||
# 2 - individual dockers
|
||||
pushd $CONTAINERS/DNS &&
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp &&
|
||||
docker build -t cetic/dns . &&
|
||||
popd &&
|
||||
|
||||
pushd $CONTAINERS/WebServer &&
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp &&
|
||||
docker build -t cetic/webserver . &&
|
||||
popd &&
|
||||
|
||||
# launch docker containers
|
||||
docker run --rm --cpuset-cpus 1 -m 128m -d -p $IP:$DNS_PORT:$DNS_PORT/udp --name DNS cetic/dns
|
||||
docker run --rm --cpuset-cpus 1 -m 128m -d -p $IP:$WEB_PORT:$WEB_PORT --name WebServer cetic/webserver
|
||||
|
||||
echo "#############################################################################"
|
||||
echo "### ###"
|
||||
echo "### Containers successfully launched. ###"
|
||||
echo "### Web server accessible on port $WEB_PORT. ###"
|
||||
echo "### DNS server accessible on port $DNS_PORT. ###"
|
||||
echo "### ###"
|
||||
echo "#############################################################################"
|
93
DEPLOYMENT/deploy_unikernels.sh
Normal file
@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
|
||||
# NB: This script assumes you cloned the project into you HOME directory.
|
||||
# If this is not the case, change the following variables accordingly
|
||||
|
||||
SRC_DIR=$HOME/unikernels
|
||||
UNIKERELS=$SRC_DIR/SOURCE/UNIKERNEL
|
||||
|
||||
# build unikernels
|
||||
pushd $UNIKERELS/DNS &&\
|
||||
mkdir -p build &&\
|
||||
pushd build &&\
|
||||
cmake .. &&\
|
||||
make &&\
|
||||
popd &&\
|
||||
|
||||
pushd $UNIKERELS/WebServer &&\
|
||||
mkdir -p build &&\
|
||||
pushd build &&\
|
||||
cmake .. &&\
|
||||
sudo make &&\
|
||||
popd &&\
|
||||
|
||||
pushd $UNIKERELS/Router &&\
|
||||
mkdir -p build &&\
|
||||
pushd build &&\
|
||||
cmake .. &&\
|
||||
make &&\
|
||||
popd &&\
|
||||
|
||||
pushd $UNIKERELS/Firewall &&\
|
||||
mkdir -p build &&\
|
||||
pushd build &&\
|
||||
cmake .. &&\
|
||||
make &&\
|
||||
popd &&\
|
||||
|
||||
# configure networks for QEMU
|
||||
# remove default bridge created
|
||||
sudo ip link del bridge43
|
||||
# create the bridge interfaces
|
||||
virsh net-define --file $UNIKERELS/internal.xml &&
|
||||
virsh net-define --file $UNIKERELS/external.xml &&
|
||||
virsh net-define --file $UNIKERELS/firewall.xml &&
|
||||
virsh net-start internal &&
|
||||
virsh net-start external &&
|
||||
virsh net-start firewall &&
|
||||
virsh net-autostart internal &&
|
||||
virsh net-autostart external &&
|
||||
virsh net-autostart firewall &&
|
||||
|
||||
# launch unikernels in QEMU (+serial output to files)
|
||||
|
||||
virt-install \
|
||||
--virt-type qemu --name DNS \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk $UNIKERELS/DNS/build/DNS.img \
|
||||
--serial file,path=/tmp/dns.log \
|
||||
--network network=internal,model=virtio \
|
||||
--noautoconsole &&
|
||||
|
||||
virt-install \
|
||||
--virt-type qemu --name WebServer \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk $UNIKERELS/WebServer/build/WebServer.img \
|
||||
--serial file,path=/tmp/web.log \
|
||||
--network network=internal,model=virtio \
|
||||
--noautoconsole &&
|
||||
|
||||
virt-install \
|
||||
--virt-type qemu --name Router \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk $UNIKERELS/Router/build/Router.img \
|
||||
--serial file,path=/tmp/router.log \
|
||||
--network network=internal,model=virtio \
|
||||
--network network=firewall,model=virtio \
|
||||
--noautoconsole &&
|
||||
|
||||
virt-install \
|
||||
--virt-type qemu --name Firewall \
|
||||
--vcpus 1 --ram 128 \
|
||||
--import --disk $UNIKERELS/Firewall/build/Firewall.img \
|
||||
--serial file,path=/tmp/firewall.log \
|
||||
--network network=external,model=virtio \
|
||||
--network network=firewall,model=virtio \
|
||||
--noautoconsole &&
|
||||
|
||||
echo "#############################################################################"
|
||||
echo "### ###"
|
||||
echo "### Unikernels successfully launched. ###"
|
||||
echo "### Serial outputs are located in /tmp. ###"
|
||||
echo "### ###"
|
||||
echo "#############################################################################"
|
30
DEPLOYMENT/pre_deployment_installation.sh
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y git &&
|
||||
|
||||
# install IncludeOS
|
||||
pushd $HOME &&
|
||||
git clone --recurse-submodules https://github.com/hioa-cs/IncludeOS &&
|
||||
popd &&
|
||||
pushd $HOME/IncludeOS &&
|
||||
sudo ./install.sh -y &&
|
||||
popd &&
|
||||
|
||||
# install libvirt
|
||||
sudo apt-get install -y libvirt-bin virtinst &&
|
||||
#NB: requires logout/login to take effect
|
||||
sudo usermod -a -G libvirtd $USER &&
|
||||
|
||||
# install Docker
|
||||
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common &&
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &&
|
||||
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" &&
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y docker-ce &&
|
||||
sudo usermod -a -G docker $USER &&
|
||||
|
||||
echo "#############################################################################"
|
||||
echo "### ###"
|
||||
echo "### /!\ You must logout/login to apply changes before continuing. /!\ ###"
|
||||
echo "### ###"
|
||||
echo "#############################################################################"
|
BIN
MEDIA/Benchmark 2.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
MEDIA/Benchmark.png
Normal file
After Width: | Height: | Size: 15 KiB |
1
MEDIA/Benchmark.xml
Normal file
@ -0,0 +1 @@
|
||||
<mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36" version="8.6.1" editor="www.draw.io" type="device"><diagram id="9f6e7cca-04d0-9da1-074d-84f045bb2cb3" name="Performance/Resilience">7VhNc5swEP01XDOAALtH23XSQzqTGR96lkEBNYL1iMUf/fWVQJjv2J0mmTQNB0a8XYF4b9/yYZFVeryTdJd8h4gJy7Wjo0W+Wq77xZurvQZOFeB7bgXEkkcVZDfAhv9iFejUaMEjlhusghBAIN91wRCyjIXYwaiUcOimPYKIOsCOxmwAbEIqhugPHmFSoXPfbvBvjMdJfWXHNpEtDZ9iCUVmrme55LHcqnBK63OZ/DyhERxaEFlbZCUBsBqlxxUTmtoubbcT0fO6JcvwmgmkmrCnomD1ist14anmorwbpvNtiywPCUe22dFQRw9KfIUlmAp15KjhIxdiBQJkOZfclpvCh+syS90ziezYgsw67xikDOVJpdTRueHM1BSpOT80Cjm1QklLHfeLAampivh87oYZNTDkjBPlDYjaMLnnigbX1iMmB8QpbXd6mB5jbZKbkOch3ORlcn6jmGLVuMtgRPPkzHaPztl6Eaw1nqOEJzZGdBWpi1bRudQMc1Xa93TLxAPkHDlkKrYFREhbCQvBYx1A0KJCgYJn6hq1w+yXkdF3uzJ69mwg45iKQfD3IjrD6maRMr45BIkJxJBRsW7QtjY/GeLJdCtaIGiaznPuQfNW5g3kscttVJ6wUDUQmYmT/OZQyNAs2TcNkcqYYac69c08q4FkgiLfd7vcGKPl1IWU9NRK2AHPMG+d+UEDjbSe3ZPW6TWfS/me3VOzWkGj7flWrpLbH3h2zyUWVOeEgmuOpzxbpGIRopbvsn+EDizPjb8lu2n9UxZrVdZ0xbRbQAYZexkXurNeM50PmykZc+ELtFIn+AguDN6tC72utD7xn3eh97ouDD5deK0Lfdt/Oxd6H8GFs3/FhcS/8Cx8ZRfOPl046UKnJ5X7hs9C/yO4cP5uXdh/w5xdeBa+8hvp/NOF17rQ897wWTjUZcmyMEmpfGp93wdCXXO51aMYz3f9P3zxD2QcEXv6x03/LYcMlR394vf/WFl12Pw7q/zZ/J8k698=</diagram><diagram id="6d5bb729-f55c-c8ed-69e5-837c886226c1" name="Orchestration">5ZrNk6MqEMD/mhyTUvErx8lksnt4r95W5bDHKUZJpAbFQvIx769fUEhCMDtuVcZsaQ5RG0T8dYPdDRPwnB+/MVhm/9IUkYnnpMcJWE48b+7H4l8KPhpB4HuNYMtw2oics2CN/0eN0NXSHU5RpWSNiFNKOC5NYUKLAiXckEHG6MGstqEkNQQl3CKjG1KwTiBBVrWfOOVZI42Di9rfEd5m+smuo0reYPK+ZXRXqOdNPLCpf01xDnVbqn6VwZQeLkTgZQKeGaW8OcuPz4hItCa21Y3SU78ZKniXG5Ra9pDskO5x3S/+oVnUb4NkfWcCFocMc7QuYSJLD0L5QpbxnIgrV5xWnNF39EwJZfXdwKl/omSDCdHyghbi9oXdWdX/PWIcHS9EqvPfEM0RZx+iiio9gVSGBoC6PpzVBrRVZRcq83RFqExle2r7jEucKGLt9MDn9E4KlgxSWGUnkjepKTrizlI2kh+3cozN8iqBaJYQuktnFWJ7nKBXoYf32pQNvDX2KF5Gd2IcXTEObca+byMO7kDYHwVhEMQPIxyMg7DrG4T9wOuNcDgKwr7jPYxwNA7CfviwWSK2CK+bV5d1iorDoj51Le7i3XgHyC3eASR4W4jLRBBDQr6QpLDw0Z5UQY7TVD6m1ScxvZZ7fAWDyLRv16YftTga9/Az5t3o21Y/GPpAm5YOKBx7dvkq+lrRn+EHA8bvBw8zftftht8fMP54/jjrt0PEVvzBcPH7ADzO+u0YU+IXVAaL24rpna4x/T14d4s4a49wl5MlkpA/uiZGdDIpbleElT1ZrVT25B6TiGt+Qtsc9KCF6j3cR7dDlPlX55nCyJwC+s0zueMIISPvCnKPAY47jhgyvpoEekVsB5FDRByFV4Fij4kQ144Uh4g4DoKHIfbsaHCQiOdmyNHnROF1jPgGnG2KXNMH7jPk0AY94nRTFJjLBX0G3C2rimNLN0Vzcz2sV+u3A8CxpZtivVvjEdZvR4pjSzfFsbnO06v125Hm0NNNVmjfZ7qpZWHNIq3x/APfEPlBK8wxlZjeKOc0b+HH6W+TT16Ln9lsmvKao3RaJQxnFspTycmXsAvKk0yB/5o0SxBeuT2erYv5F+WoQDfHvsa2Iej4pFChIlWny4TAqsKJCf/KSQdgtQLgpv9vaeomVZTqPWw3mHbM6zFEIMd7ZDTeBlI94QfFoifnb/XV2oSvv926iYruWILUXWd1fN5QEJoNcci2iFsN1Xo9vXY3VdsBxk1V47yJtS402j7ePh2mRBYsThsEL2xCbREEi/phT1XZ7GmU4wzqiw0+yllvofqzzDiXmyGfJAdvlaSFN8MJLTZYzI5slogneqsUcigOUl6JI89wMSW4QNNaMt1QNq0QncIinaZojwgtc2FlU0FnFQr/ZrV++e+1Em93gGLgv3KcI/ZaIibuy+VneOp68awstjdGeYvV/mbghzMzpgd60eXyqxfZZqxlfzD0xeV5h2VjPuddrODlFw==</diagram><diagram id="48a959eb-b0c7-ee78-ce0b-ed0e1b461dec" name="Environment">7Vpbb6M4FP41eY0AcwmPvaQ7K3WlSn3YmaeVCy54anBknCbZX7/HYC7GtJOZ0maVKQ+R+Xzl+845PoYs0FWx/0PgTf4XTwlbeE66X6DrhefF/gp+FXBogMD3GiATNG0gpwfu6b+kAd0W3dKUVBprIMk5k3RjggkvS5JIA8NC8J3Z7JGz1AA2OCMWcJ9gZqN/01TmDboKnB7/QmiWtzO7jq55wMlTJvi21PMtPPRYX011gduxdPsqxynfDSC0XqArwblsSsX+ijBFrUnbzQu13boFKeUxHfymwzNmW/3o90Q804QAqEpE6HXKQ8sNLHmjisU+U9ovE1olfFnVjavlI2WkKS/QZS4LBi1dKKa4yoma1IEbaMSuOOOiHhFF64twrfBKCv5EBjU39dXVtFoATZcwg6Sg2C1+IOyOV1RSXkLdA5eSF4MGF4xmqkLyDaB8KxktYY7WcNS8mgToQPYvEul28oDVE14QKQ7QRHdAUdB00RbfmfKut5/WfPKB6YS6G9YWm3Uj96pBQQs3LWJoaURSMGd9y4XMecZLzNY9elnbaCfIQKjvRMqD9ki8lVxx1o1wyxWJdTtSphfK0+C25CVpkBuqFjngVC3kdUZh3XwrEt1KsyGxyIgcmKjNuyAMS/psjv4WFgPLFeCJkrzA4unTGX7OGTzfOZkzRJaMlmim7e9yKsn9BtcmuAMVTa1G8uhoPiGPU1/zEOg7JoEo8CwCXTTBoOvMQKEbzBlQyJ7KrxpW5W+qvAz03R0RFBaoPKRpUcJiv/ZN1O23YZ3d4fU4dGw8+7V4tbLjVfzGeFV3hUfCh0GDDaelrAYj3ylgYDCuuf2gVTRSvBmx179b2lEmsfqxV3WpjDOOcANjML1GCzYOokWVYLJMGN+mdSiFdOQf8M+nOmkbO6TjRKvraCa3C0duF9pu5/u217Wx7C1OF39mYjNlYrEpou+gD9t82n1uSsWQwUSXDyBjmKnSn2UlcTlVYwkNZMgj/GgopoawpjwB8mpDGGtR0DSt4/fUNmjG9JQKEKrRFmKg4nIWp4u8kV7xMrAU8yYU82dwOxfNuteddDNy26PyjLvR0Ty6luV/ps8zpc+o9ZCPiGDhj3f6n8qfX86TJ8LVLOSFBnlh+0TDYNKm00bqHHsz0HfE8eMMEiWvTYxakj07Yr9XouT+HrkoCpzTUWwno2dJsWOGiqj13g+g2LMzxbOkOPZPR7GdkpwjxT5anSxQtIxOnlppd8BxXIv4/8eRZpZ8Izbpj2z6o4lkDc1BPzqOftvuz4f+GJkBJrQDzLvR/9rXswH99hHzbOhHKDqd9dtfbCbp98+Y/pV7Ouu3T4qT9NsfE86Gft8z37p/qPV/vjCeawsZxbAosFWc6XUL3Pb/7Wg+w/T/n0Hr/wA=</diagram></mxfile>
|
1
MEDIA/CETIC.xml
Normal file
@ -0,0 +1 @@
|
||||
<mxfile userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36" version="8.6.2" editor="www.draw.io" type="device"><diagram id="4ae0d6b8-8530-0065-81ea-747f68b336d0" name="Monolithic Kernel">5ZfbjpswEIafhstKgAmHy02yu63abatGVa8dmIAVg6kxIenT12BzWlLtSiXRKpuLxP5nfOCb8RAbaJUeHznOkycWATVsMzoaaG3YduC48rsWTkpwF5YSYk4iJZm9sCF/QIlWq5YkgkJrShKMUUHysRiyLINQjDTMOavGbjtGo5GQ4xgmwibEdKr+IpFIlOovzF7/CCRO2pUtU1u2ONzHnJWZXs+w0a75KHOK27m0f5HgiFUDCd0baMUZE6qVHldAa7RjbA//sHb75pCJ1wxAasAB01I/+s8CuGG7VA5fbnm9RXHSWNzfZb2v5Y5l4kPRBO1OOlhBLuO+7O2yFde/mxyHMNNcGlc33m4gQ/0YpjRXCRGg1kPrSuak1BKRUtmz9Co6y6yg7hNKV4wy3syFogX4kSP1QnC2h4HFt7fIdbv1h2A16wNwAceBpEE/AktB8JN0aU+Fjrk+E5ar+1WfYa1LMkyu1g/rpI67mfvAyoaO7fk4O5M43+U5JSEWhGU3wNbyX4bb+QzpzgF3MYH7hWw5bvb3g5WCZLKW3R7jroi9xLirjv8D2Z1A/gw8q18776tWBd7a9Lwr1yp0JtQXq1XeJNIPRJK0zc2pEJBe9ihdB+/zo3SO79mj5MzA15/wXcOB1NlvfpJjv90i39e+DubgG0z4fgVRMb4nWXyDbB3zimzbC8IA7nfOQihkVTCfcCb/mKf1o82G2XszmJ3LYZbd/srR2AbXOnT/Fw==</diagram><diagram id="1579a128-86fe-0ab2-80d5-6164026339a6" name="Unikernel">3ZZLj5swEMc/DcdKBhMIx91kd1upD6k59OzABKwYTI0JpJ++BpuX3GojNV2t4IDs/4wf85sZhIN3efsiSJl94Qkwx0NJ6+C943mRH6h3J1y1EGxcLaSCJlpCk3Cgv0CL7qDWNIHKaFqSnDNJy6UY86KAWC40IgRvlm4nzpKFUJIULOEQE2arP2giM61uN2jSPwJNs+FkFxnLkcTnVPC6MOc5Hj71jzbnZNjL+FcZSXgzk/CTg3eCc6lHebsD1qFdYnv+i3W8t4BC3rIA6wUXwmoT+kNZMhoTSXlhriivA5Y+MOiWIgc/NhmVcChJ3FkbVQdKy2TO1MxVwxMvpMmsG3VzytiOMy76vXAU7lEYKr2Sgp9hZtl6RxwEymIHY+K7gJDQziQT3AvwHKS4KpfBujWgTSG6gZk3U1pHn2yW0sGPmEpKx60nmmpggP4Zrm/B/UyPgvT3+85rSQtV4+tjPBb3a4zHrvkXyBu7ghMBlQIbMHXO41GoUdqNNMaZPMMe/Ky7luuBfqh6og/KwY3KdjIOG60gZ6H/elugwE4Z9u6QssBK2TNVKD10uFYS8jX2BL61J/w78A0tvnu40K720Se19tsa+d76Xb8H363F9yvIhoszLdIVsvXRG7KNLLb3Ixq+G6L+/yOqptPvY2+b/aLjp98=</diagram><diagram id="1f16b7f1-591d-5d02-d98e-e921793cd93b" name="network topology">7VnLcpswFP0abz08zMPLPOx0kXYy9aLtqiMLGdQAYoTwo1/fC5JsQKTNJHaSxvHClo4uEpyjI13hkXuVbW84KpLPLCLpyLGi7ci9HjnOdOLDdw3sJOB7tgRiTiMJWQdgQX8TCdoarWhESoVJSDCWClp0QczynGDRwRDnbNMNW7E06gAFiokBLDBKTfQbjUQi0dCzDvgnQuNEj2xbqmWJ8H3MWZWr8UaOu2o+sjlDui8VXyYoYpsW5M5G7hVnTMhStr0iaU1tl7b5A637++YkF4+6wFH3IXb62UkEVKgq4yJhMctROjugl83zkboHC2qJyFIo2lCEQfnue7vyow4ae7p6RzjNiCBcXfuLCLFT8qNKMIAOQ94yVqi+ViwXKswOms6ii1pmqOcsJxKZ0zTV/VZZoeJ9qJaCs/u9kkDypcmToq5kFceKCcWNQDwmKsqTUM1R6zLF7Q1h8HB8BwGcpEjQdXc6ITUr433cQRkoKHGGhVL3skZpRfTU6gkHc6moi9k2rk05xrTEbAxiAd+l+u3qFaEy2eu4AvquWMp405sbzC78mbUnr9Xi45AsV4O0rgkXFGx0i5YkvWMlFZTl0LZkQrCsFXCR0rhuELXEl3BrKc1hDO1ma0DzByWr+yTbv8qhWt1gIi9Ry5Kj65uDyYNQQknL3577fAGnxzTa2/aNa/omeC3fuE/1TUn4uvYN2ILI8jG8M28+/6N3vEnQ8Y49sQzveJ7pncB5voi2e5JdyhpP38dG5ZmG81/LcN7TDYcrTsUOHMfJBtUDPNZvqxATjIf8tgy9iWcd028nsJbjhWOvuzH5gWEuvYO0zaXDniOY/2/BWjL0mO+tZ0NrIGgcUSDnGmTFiuO8Ns+gKv25kROxYfy+HOOUVZHivy29zK6PokPYzw48LUtLhqk1kB9YR1jjbIP2d5sgBOZ65bzWehU8eb3aUIETUo7r+Vmf+YqfEjr3PKHnonDIRb5tusg9hossQ71366LwDaXZ4UeafZo0252+YJo9MVT8RpYALKQwfUXhkURXra4Qau63VVMQUtxiIKpRvE96RqOo8eYmoYIsCtRM+g1MHMOvJxDB16/n9FnH9w0RbGcgEXCOsYSZGfT1l8WHCs7EfkkVzLT4q3yDdjb8u/q1l16KBk78p+PfzMvm+lx4NgrsX3zoXMp9SQXMPX22BZYg9QFUncvORwt/2jWDdzopoHr4B6hpa/3L5s7+AA==</diagram><diagram name="deployment" id="ba9e9bd3-eff4-526b-ff8d-8600c9c1e103">7VrLluI2EP0aluNj+e1lPyBZzOT0CYtJVjnGFrbSxiKyaCBfn7Il+SV3D9NtmDMBFo11JZXkunVLj2ZmP2wOv7Bom32hCc5nlpkcZvbjzLJCx4O/FXAUgOciAaSMJAIyW2BJ/sUCRArdkQSXEhMQpzTnZNsHY1oUOOY9LGKM7vvN1jRPesA2SrEGLOMo19GvJOGZQAPXbPFfMUkzNTIyZc0qip9TRneFHG9m2ev6I6o3kbIl25dZlNB9B7LnM/uBUcrF0+bwgPPKtX23LV6pbebNcMFP6hCIHi9RvsNqyvXE+FE5AxfJXeVTKBW0APA+45scSggeS87oc+MkmP/9mhZcMor8qkzy/IHmlNXW7MTFQeI0PTs1gbWyPQ9qxAxwonHUvhVqfAUhiOkGc3aEJvuWLMVV1uFJYQznEScvffORjJm0MdeM8EQJDGyZMrwt3xZdZHQ7gdk3UdIdi7Hs1fX+NwwN7fCIpZhrduCh89YtVHP7Cs/hjefv5tlB1jQ8Dw2dj+cRVsG9S1mkjGc0pUWUz1v0vk5XuDJg9jkHFtjxj27hz6qR4ariE2YEJoeZ7Ps35vwoYyLacQpQO+RnSrfS1jB09MgDZEGqtxR2d5utbO+NxuKpkQSeqSkTkBSf8L6A/PF4OzmQetS9wZP9bTnC0rCtHjeHtFpjjZiUMTWALPB3Kb/7fCVRmTU8DuToz++8uTkmRy8O8Go96tYXzDiBVfFztML5Ey0JJ7SAuhXlnG46De5yklYVvKL4HqaWkwLGUIuzOcK5dAAYwIfvlb/sYPtOT1aWKnfSgx+MpAf74wQ6UwrtJ9ONq+sGmeNMTS4c973CKTF7qYQDusDieQrxLOrPzyge1/F74kGOqYnHdXXx+NbHSfTOskqZRvg/Xah8XXDBhfTmv19v8Y4RfgTBMbyPqgFOlds6iHEcj8ltFbiOa04ptzMoy3IDw+0vTJ6vacsKdW2pZh8h7IQDXYeGgecH6WwsBQLHCQFPPAKtsfRxUYlnlJVhbBSY7yl7Lo04p7tE+r9LvTgsT8JDMNwduIqWDg3hG8eHj9AQXvH+QN3idPOVfaF8pcZ+R8LaEx5nuDSqAK3ucLZ/Ceja9wkDGQVjMvKQLiN7AhkhpLF3RTqyfuBGWw1+22lPvdO2w8vttJF+0fAVrwBYCmKGjMJb8rGLP0WEDP8uaxKKpG9j8ErN+NDpG5IktTz3GeF4uY3qMN9D4GiSPQMJnrpxV8cdz9NIQNbIZsCaIos5GguPvy1vLFgOuiQL+t3B7+IW7Wr8b7v9fzjYI4f+8/nf0/y/UGfDq2GgychqO2VfkgH9ND8/gJdg9wOoPJtdDxde2BeDe0EqrLFzipdz+aY9Brx/dlRVfCprH9xBA+RtD20lPKXVN24IFdZWTNWg0DKQFxjINA0YfVHdYYs2UBCDioZ61+uJiWB4d+Prhx3kj5x2prg0UNOdPCiaO7g3ggKJoAhvQTFyo+f8yKgYO4lNERWkeDVVQIYwblni1YBwBvvYM4YDFNufA4lfBLQ/ubLn/wE=</diagram></mxfile>
|
BIN
MEDIA/PoC Topology.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
MEDIA/hypervisor_container_unikernel.jpg
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
MEDIA/mutable-vs-immutable-update.PNG
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
MEDIA/normal_application_stack.PNG
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
MEDIA/unikernel_application_stack.PNG
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
MEDIA/unikernel_network.PNG
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
MEDIA/vms-containers-unikernels.PNG
Normal file
After Width: | Height: | Size: 20 KiB |
5
SOURCE/CONTAINER/DNS/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM alpine:latest
|
||||
RUN mkdir /service
|
||||
COPY runnableService /service
|
||||
WORKDIR /service
|
||||
CMD sleep 1 && ./runnableService "$(hostname -i)"
|
3
SOURCE/CONTAINER/DNS/compile.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp
|
3
SOURCE/CONTAINER/DNS/create_container.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build -t cetic/dns .
|
283
SOURCE/CONTAINER/DNS/dnsServer.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
/**
|
||||
* Basic DNS server for the IncludeOS unikernel framework.
|
||||
*
|
||||
* This code uses portions of code created by GitHub user tomasorti for his dns-server project (https://github.com/tomasorti/dns-server)
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define SERVER_PORT 53
|
||||
#define BUFFER_SIZE 1024
|
||||
|
||||
static const unsigned int QR_MASK = 0x8000;
|
||||
static const unsigned int OPCODE_MASK = 0x7800;
|
||||
static const unsigned int AA_MASK = 0x0400;
|
||||
static const unsigned int TC_MASK = 0x0200;
|
||||
static const unsigned int RD_MASK = 0x0100;
|
||||
static const unsigned int RA_MASK = 0x8000;
|
||||
static const unsigned int RCODE_MASK = 0x000F;
|
||||
static const unsigned int HDR_OFFSET = 12;
|
||||
|
||||
// for more info on DNS fields, see RFC 1035
|
||||
|
||||
struct queryHeader {
|
||||
unsigned int id; // 16 bit identifier assigned by the program who generated the query
|
||||
unsigned int query; // identifies if message is query (0) or a response (1)
|
||||
unsigned int opcode; // 4 bit field specifying kind of query: standard (0), inverse (1), server status request (2), reserved (3-15)
|
||||
unsigned int aa; // bit indicating if responding server is an authority for the domain name
|
||||
unsigned int truncation; // specifies whether this message was truncated or not
|
||||
unsigned int recursionDesired; // may be set in a query, directs the name server to pursue the query recursively
|
||||
unsigned int recursionAvailable; // set in a response, indicates whether recursive queries are available
|
||||
unsigned int responseCode; // 4 bit response code: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused
|
||||
|
||||
// unsigned 16-bit integers
|
||||
unsigned int questionCount; // number of entries in the question section
|
||||
unsigned int answerCount; // number of resource reconds in the answer section
|
||||
unsigned int nameServerCount; // number of name server resource records in the authority records section
|
||||
unsigned int additionalResourceCount; // number of resource records in the additional records section
|
||||
};
|
||||
|
||||
struct queryQuestion {
|
||||
std::string queryName; // domain name requested
|
||||
unsigned int queryType; // 2 octet code specifying the type of the query
|
||||
unsigned int queryClass; // 2 octet code specifying the class of the query
|
||||
};
|
||||
|
||||
queryHeader pQueryHeader;
|
||||
queryQuestion pQueryQuestion;
|
||||
std::map<std::string,std::vector<int>> resourceRecords;
|
||||
|
||||
unsigned int get16bits(char*& buffer) {
|
||||
unsigned int value = static_cast<unsigned char> (buffer[0]);
|
||||
value = value << 8;
|
||||
value += static_cast<unsigned char> (buffer[1]);
|
||||
buffer += 2;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void put8bits(char*& buffer, unsigned int value) throw () {
|
||||
buffer[0] = (value);
|
||||
buffer += 1;
|
||||
}
|
||||
|
||||
void put16bits(char*& buffer, unsigned int value) throw () {
|
||||
buffer[0] = (value & 0xFF00) >> 8;
|
||||
buffer[1] = value & 0xFF;
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
void put32bits(char*& buffer, unsigned long value) throw () {
|
||||
buffer[0] = (value & 0xFF000000) >> 24;
|
||||
buffer[1] = (value & 0xFF0000) >> 16;
|
||||
buffer[2] = (value & 0xFF00) >> 16;
|
||||
buffer[3] = (value & 0xFF) >> 16;
|
||||
buffer += 4;
|
||||
}
|
||||
|
||||
queryHeader decodeHeader(char* data, queryHeader pQueryHeader){
|
||||
pQueryHeader.id = get16bits(data);
|
||||
|
||||
unsigned int fields = get16bits(data);
|
||||
pQueryHeader.query = fields & QR_MASK;
|
||||
pQueryHeader.opcode = fields & OPCODE_MASK;
|
||||
pQueryHeader.aa = fields & AA_MASK;
|
||||
pQueryHeader.truncation = fields & TC_MASK;
|
||||
pQueryHeader.recursionDesired = fields & RD_MASK;
|
||||
pQueryHeader.recursionAvailable = fields & RA_MASK;
|
||||
|
||||
pQueryHeader.questionCount = get16bits(data);
|
||||
pQueryHeader.answerCount = get16bits(data);
|
||||
pQueryHeader.nameServerCount = get16bits(data);
|
||||
pQueryHeader.additionalResourceCount = get16bits(data);
|
||||
return pQueryHeader;
|
||||
}
|
||||
|
||||
queryQuestion decodeQuery(char*& data, queryQuestion pQueryQuestion){
|
||||
pQueryQuestion.queryName = "";
|
||||
|
||||
int length = *data++;
|
||||
while (length != 0) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = *data++;
|
||||
pQueryQuestion.queryName.append(1, c);
|
||||
}
|
||||
length = *data++;
|
||||
if (length != 0) pQueryQuestion.queryName.append(1,'.');
|
||||
}
|
||||
|
||||
pQueryQuestion.queryType = get16bits(data);
|
||||
pQueryQuestion.queryClass = get16bits(data);
|
||||
return pQueryQuestion;
|
||||
}
|
||||
|
||||
void codeDomain(char*& buffer, const std::string& domain) {
|
||||
int start = 0, end; // indexes
|
||||
while ((end = domain.find('.', start)) != std::string::npos) {
|
||||
*buffer++ = end - start; // label length octet
|
||||
for (int i=start; i<end; i++) {
|
||||
*buffer++ = domain[i]; // label octets
|
||||
}
|
||||
start = end + 1; // Skip '.'
|
||||
}
|
||||
|
||||
*buffer++ = domain.size() - start; // last label length octet
|
||||
for (int i=start; i<domain.size(); i++) {
|
||||
*buffer++ = domain[i]; // last label octets
|
||||
}
|
||||
*buffer++ = 0;
|
||||
}
|
||||
|
||||
|
||||
int processQuery(char* buffer, queryHeader pQueryHeader, queryQuestion pQueryQuestion){
|
||||
|
||||
// search for domain in resourceRecords
|
||||
bool bRRexists = true;
|
||||
std::map<std::string,std::vector<int>>::iterator record = resourceRecords.find(pQueryQuestion.queryName);
|
||||
if (record == resourceRecords.end())
|
||||
bRRexists = false;
|
||||
|
||||
char* bufferBegin = buffer;
|
||||
|
||||
// create header
|
||||
put16bits(buffer, pQueryHeader.id);
|
||||
|
||||
int fields = (1 << 15); // Response code
|
||||
fields += (0 << 11); // Opcode
|
||||
fields += (0 << 10); // Authoritative code
|
||||
fields += (0 << 9); // Truncated code
|
||||
fields += (1 << 8); // Recursion desired code
|
||||
fields += (0 << 7); // Recursion available code
|
||||
fields += (0 << 6); // Z reserved code
|
||||
fields += (0 << 5); // Answers authenticated code
|
||||
fields += (0 << 4); // Non-authenticated data code
|
||||
if(bRRexists && pQueryQuestion.queryType == 1)
|
||||
fields += 0; // Reply code
|
||||
else
|
||||
fields += 3;
|
||||
put16bits(buffer, fields);
|
||||
|
||||
put16bits(buffer, pQueryHeader.questionCount); // Questions count
|
||||
if(bRRexists && pQueryQuestion.queryType == 1)
|
||||
put16bits(buffer, 1); // Answers count
|
||||
else
|
||||
put16bits(buffer, 0);
|
||||
put16bits(buffer, 0); // Authority RRs
|
||||
put16bits(buffer, 0); // Additional RRs
|
||||
|
||||
// create domain query section - copy original question format
|
||||
codeDomain(buffer, pQueryQuestion.queryName);
|
||||
put16bits(buffer, pQueryQuestion.queryType);
|
||||
put16bits(buffer, pQueryQuestion.queryClass);
|
||||
|
||||
// if requested domain exists in resourceRecords, create the answer
|
||||
if(bRRexists && pQueryQuestion.queryType == 1){
|
||||
// compression code to pointing to original question - should be offset from ID to domain name (in number of 16bits)
|
||||
put16bits(buffer, 49164);
|
||||
|
||||
put16bits(buffer, pQueryQuestion.queryType);
|
||||
put16bits(buffer, pQueryQuestion.queryClass);
|
||||
put32bits(buffer, 0); // time to live
|
||||
|
||||
put16bits(buffer, 4); // data length (always 4 for IPv4 addresses)
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][0]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][1]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][2]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][3]);
|
||||
}
|
||||
|
||||
int size = buffer - bufferBegin;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
resourceRecords["www.cetic.be"].push_back(10);
|
||||
resourceRecords["www.cetic.be"].push_back(0);
|
||||
resourceRecords["www.cetic.be"].push_back(0);
|
||||
resourceRecords["www.cetic.be"].push_back(5);
|
||||
resourceRecords["cetic.be"].push_back(10);
|
||||
resourceRecords["cetic.be"].push_back(0);
|
||||
resourceRecords["cetic.be"].push_back(0);
|
||||
resourceRecords["cetic.be"].push_back(5);
|
||||
resourceRecords["internship.cetic.be"].push_back(10);
|
||||
resourceRecords["internship.cetic.be"].push_back(0);
|
||||
resourceRecords["internship.cetic.be"].push_back(0);
|
||||
resourceRecords["internship.cetic.be"].push_back(5);
|
||||
|
||||
// define address and socket variables
|
||||
struct sockaddr_in serverAddress;
|
||||
int serverSocket;
|
||||
struct sockaddr_in clienAddress;
|
||||
socklen_t clientAddressLength = sizeof(clienAddress);
|
||||
int bytesReceivedLength;
|
||||
char receiveBuffer[BUFFER_SIZE];
|
||||
|
||||
// creating UDP socket
|
||||
if ((serverSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
perror("cannot create socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// defining server address properties
|
||||
memset((void *)&serverAddress, 0, sizeof(serverAddress));
|
||||
serverAddress.sin_family = AF_INET;
|
||||
serverAddress.sin_addr.s_addr = inet_addr(argv[1]);
|
||||
//serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serverAddress.sin_port = htons(SERVER_PORT);
|
||||
|
||||
// binding to UDP socket
|
||||
if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) {
|
||||
perror("bind failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Service IP address is %s on port %d\n", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port));
|
||||
|
||||
for (;;) {
|
||||
bytesReceivedLength = recvfrom(serverSocket, receiveBuffer, BUFFER_SIZE, 0, (struct sockaddr *)&clienAddress, &clientAddressLength);
|
||||
printf("received %d bytes\n", bytesReceivedLength);
|
||||
if (bytesReceivedLength > 0) {
|
||||
char* data = &receiveBuffer[0];
|
||||
|
||||
pQueryHeader = decodeHeader(data, pQueryHeader);
|
||||
data += HDR_OFFSET;
|
||||
pQueryQuestion = decodeQuery(data, pQueryQuestion);
|
||||
|
||||
// debug output
|
||||
printf("####### INCOMMING REQUEST #######\n");
|
||||
printf("Getting UDP data from %s:%d\n", inet_ntoa(clienAddress.sin_addr), ntohs(clienAddress.sin_port));
|
||||
printf("Header:\n");
|
||||
printf("\tID: %u\n",pQueryHeader.id);
|
||||
printf("\tQuery: %u\n", pQueryHeader.query);
|
||||
printf("\topCode: %u\n", pQueryHeader.opcode);
|
||||
printf("\tAA: %u\n", pQueryHeader.aa);
|
||||
printf("\tTruncation: %u\n", pQueryHeader.truncation);
|
||||
printf("\tRecursion Desired: %u\n", pQueryHeader.recursionDesired);
|
||||
printf("\tRecursion Available: %u\n", pQueryHeader.recursionAvailable);
|
||||
printf("\tReponse Code: %u\n", pQueryHeader.responseCode);
|
||||
printf("\tQuestion Count: %u\n", pQueryHeader.questionCount);
|
||||
printf("\tAnswer Count: %u\n", pQueryHeader.answerCount);
|
||||
printf("\tName Server Count: %u\n", pQueryHeader.nameServerCount);
|
||||
printf("\tAdditional Resource Count: %u\n", pQueryHeader.additionalResourceCount);
|
||||
printf("Query:\n");
|
||||
printf("\tQuery name: %s\n", pQueryQuestion.queryName.data());
|
||||
printf("\tQuery Type: %u\n", pQueryQuestion.queryType);
|
||||
printf("\tAdditional Resource Count: %u\n", pQueryQuestion.queryClass);
|
||||
printf("#################################\n");
|
||||
|
||||
// send reply
|
||||
char buffer[BUFFER_SIZE];
|
||||
int nbrBytes = processQuery(buffer, pQueryHeader, pQueryQuestion);
|
||||
|
||||
sendto(serverSocket, buffer, nbrBytes, 0, (struct sockaddr *)&clienAddress, clientAddressLength);
|
||||
}
|
||||
}
|
||||
}
|
3
SOURCE/CONTAINER/DNS/run_service.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker run --rm -d cetic/dns
|
10
SOURCE/CONTAINER/DNS/start.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Building binary from C++ code (statically linking libraries)
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp
|
||||
|
||||
# Building the container (expecting the Dockerfile to be present)
|
||||
docker build -t cetic/dns .
|
||||
|
||||
# Launching the service in a Docker container
|
||||
docker run --rm -d cetic/dns
|
2
SOURCE/CONTAINER/Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
FROM alpine:latest
|
||||
RUN apk add --no-cache gcc g++
|
45
SOURCE/CONTAINER/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Container Code
|
||||
|
||||
This folder contains the container version of the unikernel services.
|
||||
|
||||
Each folder holds:
|
||||
* The CPP file containing the code
|
||||
* A **compile.sh** script to compile the CPP file into a runnable service
|
||||
* A **Dockerfile** to create the container for this service
|
||||
* A **create_container.sh** script to create to container from the Dockerfile
|
||||
* A **run_service.sh** script to run the created container in detached mode
|
||||
* A **start.sh** script that will compile the binary from code, build the Docker container and run it (in detached mode)
|
||||
|
||||
The following section briefly explains the steps taken.
|
||||
|
||||
## Pre Requisite
|
||||
|
||||
Before running the **compile.sh** or **start.sh** scripts, you must first build the **builder** container from the Dockerfile in this parent folder.
|
||||
|
||||
This can be done by running the **create_compiler.sh** script or running the following command from the CONTAINER directory:
|
||||
|
||||
```
|
||||
docker build -t cetic/compiler .
|
||||
```
|
||||
|
||||
## Compiling the binary (*compile.sh*)
|
||||
|
||||
*Requires the cetic/compiler container image*
|
||||
|
||||
This script will launch a new cetic/compiler image container, mapping the current folder to a folder inside the container, then it will staticaly compile the C++ code in the .cpp file in the directory and output a *runnableService* binary.
|
||||
|
||||
## Creating the container
|
||||
|
||||
This will create the service container using the **Dockerfile**.
|
||||
|
||||
It will use the lastest version of alpine base image and copy the **runnableService** executable inside the container.
|
||||
|
||||
## Running the container
|
||||
|
||||
When running the container, it will execute the command instructed in the **Dockerfile**.
|
||||
|
||||
The container will wait for the network to be up (sleep 1) then it will launch the service binary, passing the container's IP address to bind the service to as a paramater.
|
||||
|
||||
The script starts it in detached mode (i.e.: in the background)
|
||||
|
||||
**NB:** as of now, the IP address is not given statically, you must run `docker network inspect bridge` to view the IP address assigned to the container.
|
6
SOURCE/CONTAINER/WebServer/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
FROM alpine:latest
|
||||
RUN mkdir /service
|
||||
COPY runnableService /service
|
||||
COPY index.html /service
|
||||
WORKDIR /service
|
||||
CMD sleep 1 && ./runnableService "$(hostname -i)"
|
3
SOURCE/CONTAINER/WebServer/compile.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp
|
3
SOURCE/CONTAINER/WebServer/create_container.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build -t cetic/webserver .
|
15
SOURCE/CONTAINER/WebServer/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>CETIC Internship Unikernel Web Page</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu:500,300" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="font-family: Arial, sans-serif">
|
||||
CETIC Internship Unikernel Web Page
|
||||
</h1>
|
||||
<hr />
|
||||
<p>This is the first web server spawn from a unikernel during the CETIC Intership 2017-18</p>
|
||||
</body>
|
||||
</html>
|
3
SOURCE/CONTAINER/WebServer/run_service.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker run --rm -d cetic/webserver
|
10
SOURCE/CONTAINER/WebServer/start.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Building binary from C++ code (statically linking libraries)
|
||||
docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp
|
||||
|
||||
# Building the container (expecting the Dockerfile to be present)
|
||||
docker build -t cetic/webserver .
|
||||
|
||||
# Launching the service in a Docker container
|
||||
docker run --rm -d cetic/webserver
|
120
SOURCE/CONTAINER/WebServer/webServer.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This code is adapted from the IncludeOS Acorn web server example.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#define SERVER_PORT 80
|
||||
#define BUFFER_SIZE 2048
|
||||
|
||||
bool isIndexRequested(char receiveBuffer[]) {
|
||||
// if only / is requested
|
||||
if(receiveBuffer[4] == '/' && receiveBuffer[5] == ' ')
|
||||
return true;
|
||||
|
||||
// if only /index.html is requested
|
||||
char request[25];
|
||||
memcpy(request, receiveBuffer, 24);
|
||||
request[25] = '\0';
|
||||
|
||||
char *output = NULL;
|
||||
output = strstr(request," /index.html ");
|
||||
if(output)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// define address and socket variables
|
||||
struct sockaddr_in serverAddress;
|
||||
int serverSocket;
|
||||
int clientSocket;
|
||||
struct sockaddr_in clientAddress;
|
||||
socklen_t clientAddressLength = sizeof(clientAddress);
|
||||
int bytesReceivedLength;
|
||||
char receiveBuffer[BUFFER_SIZE];
|
||||
|
||||
// Retrieve the HTML page from the disk
|
||||
std::ifstream file("index.html", std::ios::binary | std::ios::ate);
|
||||
std::streamsize indexLength = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
char indexArray[indexLength];
|
||||
file.read(indexArray, indexLength);
|
||||
|
||||
// creating error message
|
||||
std::string error = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<html><body>Page not found</body></html>\r\n";
|
||||
int errorLength = error.length();
|
||||
// declaring character array
|
||||
char errorArray[errorLength+1];
|
||||
strcpy(errorArray, error.c_str());
|
||||
|
||||
|
||||
// creating TCP socket
|
||||
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
perror("cannot create socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// defining server address properties
|
||||
memset((void *)&serverAddress, 0, sizeof(serverAddress));
|
||||
serverAddress.sin_family = AF_INET;
|
||||
serverAddress.sin_addr.s_addr = inet_addr(argv[1]);
|
||||
//serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serverAddress.sin_port = htons(SERVER_PORT);
|
||||
|
||||
// binding to UDP socket
|
||||
if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) {
|
||||
perror("bind failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set the socket for listening (queue backlog of 5)
|
||||
if (listen(serverSocket, 5) < 0) {
|
||||
perror("listen failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Service IP address is %s on port %d\n", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port));
|
||||
|
||||
for (;;) {
|
||||
clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, &clientAddressLength);
|
||||
|
||||
bytesReceivedLength = read(clientSocket, receiveBuffer, BUFFER_SIZE);
|
||||
|
||||
printf("####### INCOMMING REQUEST #######\n");
|
||||
printf("Received a connection from: %s port %d\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port));
|
||||
printf("received %d bytes\n", bytesReceivedLength);
|
||||
|
||||
if (bytesReceivedLength > 0) {
|
||||
|
||||
// TODO respond only to GET and / or /index.html
|
||||
if(receiveBuffer[0] == 'G' && isIndexRequested(receiveBuffer) ) { //request is not a GET
|
||||
// debug output
|
||||
printf("%s", receiveBuffer);
|
||||
|
||||
// send reply
|
||||
//printf("%s", indexArray);
|
||||
int nbytes = write(clientSocket, indexArray, indexLength);
|
||||
printf("%d sent to client\n", nbytes);
|
||||
} else {
|
||||
printf("%s", receiveBuffer);
|
||||
int nbytes = write(clientSocket, errorArray, (errorLength+1));
|
||||
printf("%d bytes sent to client\n", nbytes);
|
||||
}
|
||||
|
||||
printf("#################################\n");
|
||||
shutdown(clientSocket, 2);
|
||||
}
|
||||
}
|
||||
}
|
3
SOURCE/CONTAINER/create_compiler.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build -t cetic/compiler .
|
21
SOURCE/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Source Code
|
||||
|
||||
This folder contains the source code of the unikernel projects created with the [IncludeOS framework](https://github.com/hioa-cs/IncludeOS)
|
||||
|
||||
Each folder contains the source code for a single unikernel.
|
||||
|
||||
## Building Unikernel Image
|
||||
|
||||
**Requires IncludeOS to be installed on the system**
|
||||
|
||||
The script **cmake_build.sh** can be executed to build the each unikernel images. The .img disk file will be located in the **build** folder inside the project folder.
|
||||
|
||||
## Container Versions
|
||||
|
||||
The **CONTAINER** folder contains the container versions of the unikernel images.
|
||||
|
||||
The container versions are aimed to be analogs of the unikernel code but adapted to run in a standalone Docker container.
|
||||
|
||||
## Deployment
|
||||
|
||||
For deploying the unikernel or container environment, see the [DEPLOYMENT](https://git.cetic.be/stages/unikernels/tree/feature/stagelongree2018/DEPLOYMENT) folder for deployment scripts.
|
36
SOURCE/UNIKERNEL/DNS/CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
|
||||
# IncludeOS install location
|
||||
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
|
||||
set(ENV{INCLUDEOS_PREFIX} /usr/local)
|
||||
endif()
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
|
||||
project (DNS)
|
||||
|
||||
# Human-readable name of your service
|
||||
set(SERVICE_NAME "CETIC DNS Service")
|
||||
|
||||
# Name of your service binary
|
||||
set(BINARY "DNS")
|
||||
|
||||
# Source files to be linked with OS library parts to form bootable image
|
||||
set(SOURCES
|
||||
service.cpp # ...add more here
|
||||
)
|
||||
|
||||
# To add your own include paths:
|
||||
# set(LOCAL_INCLUDES ".")
|
||||
|
||||
# DRIVERS / PLUGINS:
|
||||
|
||||
set(DRIVERS
|
||||
virtionet # Virtio networking
|
||||
# virtioblock # Virtio block device
|
||||
# ... Others from src/drivers
|
||||
)
|
||||
|
||||
set(PLUGINS
|
||||
)
|
||||
|
||||
# include service build script
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
|
7
SOURCE/UNIKERNEL/DNS/cmake_build.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
pushd build
|
||||
cmake ..
|
||||
make
|
||||
popd
|
11
SOURCE/UNIKERNEL/DNS/config.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"net": [
|
||||
{
|
||||
"iface": 0,
|
||||
"config": "static",
|
||||
"address": "10.0.0.100",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "10.0.0.254"
|
||||
}
|
||||
]
|
||||
}
|
262
SOURCE/UNIKERNEL/DNS/service.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
/**
|
||||
* Basic DNS server for the IncludeOS unikernel framework.
|
||||
*
|
||||
* This code uses portions of code created by GitHub user tomasorti for his dns-server project (https://github.com/tomasorti/dns-server)
|
||||
*/
|
||||
|
||||
#include <service>
|
||||
#include <net/inet4>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace net;
|
||||
|
||||
#define SERVER_PORT 53
|
||||
|
||||
static const uint QR_MASK = 0x8000;
|
||||
static const uint OPCODE_MASK = 0x7800;
|
||||
static const uint AA_MASK = 0x0400;
|
||||
static const uint TC_MASK = 0x0200;
|
||||
static const uint RD_MASK = 0x0100;
|
||||
static const uint RA_MASK = 0x8000;
|
||||
static const uint RCODE_MASK = 0x000F;
|
||||
static const uint HDR_OFFSET = 12;
|
||||
static const int BUFFER_SIZE = 1024;
|
||||
|
||||
// for more info on DNS fields, see RFC 1035
|
||||
|
||||
struct queryHeader {
|
||||
uint id; // 16 bit identifier assigned by the program who generated the query
|
||||
uint query; // identifies if message is query (0) or a response (1)
|
||||
uint opcode; // 4 bit field specifying kind of query: standard (0), inverse (1), server status request (2), reserved (3-15)
|
||||
uint aa; // bit indicating if responding server is an authority for the domain name
|
||||
uint truncation; // specifies whether this message was truncated or not
|
||||
uint recursionDesired; // may be set in a query, directs the name server to pursue the query recursively
|
||||
uint recursionAvailable; // set in a response, indicates whether recursive queries are available
|
||||
uint responseCode; // 4 bit response code: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused
|
||||
|
||||
// unsigned 16-bit integers
|
||||
uint questionCount; // number of entries in the question section
|
||||
uint answerCount; // number of resource reconds in the answer section
|
||||
uint nameServerCount; // number of name server resource records in the authority records section
|
||||
uint additionalResourceCount; // number of resource records in the additional records section
|
||||
};
|
||||
|
||||
struct queryQuestion {
|
||||
std::string queryName; // domain name requested
|
||||
uint queryType; // 2 octet code specifying the type of the query
|
||||
uint queryClass; // 2 octet code specifying the class of the query
|
||||
};
|
||||
|
||||
queryHeader pQueryHeader;
|
||||
queryQuestion pQueryQuestion;
|
||||
std::map<std::string,std::vector<int>> resourceRecords;
|
||||
|
||||
uint get16bits(const char*& buffer) {
|
||||
uint value = static_cast<u_char> (buffer[0]);
|
||||
value = value << 8;
|
||||
value += static_cast<u_char> (buffer[1]);
|
||||
buffer += 2;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void put8bits(char*& buffer, uint value) throw () {
|
||||
buffer[0] = (value);
|
||||
buffer += 1;
|
||||
}
|
||||
|
||||
void put16bits(char*& buffer, uint value) throw () {
|
||||
buffer[0] = (value & 0xFF00) >> 8;
|
||||
buffer[1] = value & 0xFF;
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
void put32bits(char*& buffer, ulong value) throw () {
|
||||
buffer[0] = (value & 0xFF000000) >> 24;
|
||||
buffer[1] = (value & 0xFF0000) >> 16;
|
||||
buffer[2] = (value & 0xFF00) >> 16;
|
||||
buffer[3] = (value & 0xFF) >> 16;
|
||||
buffer += 4;
|
||||
}
|
||||
|
||||
queryHeader decodeHeader(const char* data, queryHeader pQueryHeader){
|
||||
pQueryHeader.id = get16bits(data);
|
||||
|
||||
uint fields = get16bits(data);
|
||||
pQueryHeader.query = fields & QR_MASK;
|
||||
pQueryHeader.opcode = fields & OPCODE_MASK;
|
||||
pQueryHeader.aa = fields & AA_MASK;
|
||||
pQueryHeader.truncation = fields & TC_MASK;
|
||||
pQueryHeader.recursionDesired = fields & RD_MASK;
|
||||
pQueryHeader.recursionAvailable = fields & RA_MASK;
|
||||
|
||||
pQueryHeader.questionCount = get16bits(data);
|
||||
pQueryHeader.answerCount = get16bits(data);
|
||||
pQueryHeader.nameServerCount = get16bits(data);
|
||||
pQueryHeader.additionalResourceCount = get16bits(data);
|
||||
return pQueryHeader;
|
||||
}
|
||||
|
||||
queryQuestion decodeQuery(const char*& data, queryQuestion pQueryQuestion){
|
||||
pQueryQuestion.queryName = "";
|
||||
|
||||
int length = *data++;
|
||||
while (length != 0) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = *data++;
|
||||
pQueryQuestion.queryName.append(1, c);
|
||||
}
|
||||
length = *data++;
|
||||
if (length != 0) pQueryQuestion.queryName.append(1,'.');
|
||||
}
|
||||
|
||||
pQueryQuestion.queryType = get16bits(data);
|
||||
pQueryQuestion.queryClass = get16bits(data);
|
||||
return pQueryQuestion;
|
||||
}
|
||||
|
||||
void codeDomain(char*& buffer, const std::string& domain) {
|
||||
int start = 0, end; // indexes
|
||||
while ((end = domain.find('.', start)) != std::string::npos) {
|
||||
*buffer++ = end - start; // label length octet
|
||||
for (int i=start; i<end; i++) {
|
||||
*buffer++ = domain[i]; // label octets
|
||||
}
|
||||
start = end + 1; // Skip '.'
|
||||
}
|
||||
|
||||
*buffer++ = domain.size() - start; // last label length octet
|
||||
for (int i=start; i<domain.size(); i++) {
|
||||
*buffer++ = domain[i]; // last label octets
|
||||
}
|
||||
*buffer++ = 0;
|
||||
}
|
||||
|
||||
|
||||
int processQuery(char* buffer, queryHeader pQueryHeader, queryQuestion pQueryQuestion){
|
||||
|
||||
// search for domain in resourceRecords
|
||||
bool bRRexists = true;
|
||||
std::map<std::string,std::vector<int>>::iterator record = resourceRecords.find(pQueryQuestion.queryName);
|
||||
if (record == resourceRecords.end())
|
||||
bRRexists = false;
|
||||
|
||||
|
||||
char* bufferBegin = buffer;
|
||||
|
||||
// create header
|
||||
put16bits(buffer, pQueryHeader.id);
|
||||
|
||||
int fields = (1 << 15); // Response code
|
||||
fields += (0 << 11); // Opcode
|
||||
fields += (0 << 10); // Authoritative code
|
||||
fields += (0 << 9); // Truncated code
|
||||
fields += (1 << 8); // Recursion desired code
|
||||
fields += (0 << 7); // Recursion available code
|
||||
fields += (0 << 6); // Z reserved code
|
||||
fields += (0 << 5); // Answers authenticated code
|
||||
fields += (0 << 4); // Non-authenticated data code
|
||||
if(bRRexists)
|
||||
fields += 0; // Reply code
|
||||
else
|
||||
fields += 3;
|
||||
put16bits(buffer, fields);
|
||||
|
||||
put16bits(buffer, pQueryHeader.questionCount); // Questions count
|
||||
if(bRRexists)
|
||||
put16bits(buffer, 1); // Answers count
|
||||
else
|
||||
put16bits(buffer, 0);
|
||||
put16bits(buffer, 0); // Authority RRs
|
||||
put16bits(buffer, 0); // Additional RRs
|
||||
|
||||
// create domain query section - copy original question format
|
||||
codeDomain(buffer, pQueryQuestion.queryName);
|
||||
put16bits(buffer, pQueryQuestion.queryType);
|
||||
put16bits(buffer, pQueryQuestion.queryClass);
|
||||
|
||||
// if requested domain exists in resourceRecords, create the answer
|
||||
if(bRRexists){
|
||||
// compression code to pointing to original question - should be offset from ID to domain name (in number of 16bits)
|
||||
put16bits(buffer, 49164);
|
||||
|
||||
put16bits(buffer, pQueryQuestion.queryType);
|
||||
put16bits(buffer, pQueryQuestion.queryClass);
|
||||
put32bits(buffer, 0); // time to live
|
||||
|
||||
put16bits(buffer, 4); // data length (always 4 for IPv4 addresses)
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][0]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][1]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][2]);
|
||||
put8bits(buffer,resourceRecords[pQueryQuestion.queryName][3]);
|
||||
}
|
||||
|
||||
int size = buffer - bufferBegin;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
resourceRecords["www.cetic.be"].push_back(10);
|
||||
resourceRecords["www.cetic.be"].push_back(0);
|
||||
resourceRecords["www.cetic.be"].push_back(0);
|
||||
resourceRecords["www.cetic.be"].push_back(5);
|
||||
resourceRecords["cetic.be"].push_back(10);
|
||||
resourceRecords["cetic.be"].push_back(0);
|
||||
resourceRecords["cetic.be"].push_back(0);
|
||||
resourceRecords["cetic.be"].push_back(5);
|
||||
resourceRecords["internship.cetic.be"].push_back(10);
|
||||
resourceRecords["internship.cetic.be"].push_back(0);
|
||||
resourceRecords["internship.cetic.be"].push_back(0);
|
||||
resourceRecords["internship.cetic.be"].push_back(5);
|
||||
|
||||
// get the first network interfaces of the unikernel
|
||||
auto& inet = Inet4::stack<0>();
|
||||
Expects(inet.is_configured());
|
||||
|
||||
printf("Service IP address is %s\n", inet.ip_addr().str().c_str());
|
||||
|
||||
const UDP::port_t port = SERVER_PORT;
|
||||
auto& sock = inet.udp().bind(port);
|
||||
|
||||
sock.on_read(
|
||||
[&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len){
|
||||
|
||||
pQueryHeader = decodeHeader(data, pQueryHeader);
|
||||
data += HDR_OFFSET;
|
||||
pQueryQuestion = decodeQuery(data, pQueryQuestion);
|
||||
|
||||
// debug output
|
||||
printf("####### INCOMMING REQUEST #######\n");
|
||||
printf("Getting UDP data from %s:%d\n", addr.str().c_str(), port);
|
||||
printf("Header:\n");
|
||||
printf("\tID: %u\n",pQueryHeader.id);
|
||||
printf("\tQuery: %u\n", pQueryHeader.query);
|
||||
printf("\topCode: %u\n", pQueryHeader.opcode);
|
||||
printf("\tAA: %u\n", pQueryHeader.aa);
|
||||
printf("\tTruncation: %u\n", pQueryHeader.truncation);
|
||||
printf("\tRecursion Desired: %u\n", pQueryHeader.recursionDesired);
|
||||
printf("\tRecursion Available: %u\n", pQueryHeader.recursionAvailable);
|
||||
printf("\tReponse Code: %u\n", pQueryHeader.responseCode);
|
||||
printf("\tQuestion Count: %u\n", pQueryHeader.questionCount);
|
||||
printf("\tAnswer Count: %u\n", pQueryHeader.answerCount);
|
||||
printf("\tName Server Count: %u\n", pQueryHeader.nameServerCount);
|
||||
printf("\tAdditional Resource Count: %u\n", pQueryHeader.additionalResourceCount);
|
||||
printf("Query:\n");
|
||||
printf("\tQuery name: %s\n", pQueryQuestion.queryName.data());
|
||||
printf("\tQuery Type: %u\n", pQueryQuestion.queryType);
|
||||
printf("\tAdditional Resource Count: %u\n", pQueryQuestion.queryClass);
|
||||
printf("#################################\n");
|
||||
|
||||
// send reply
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
int nbrBytes = processQuery(buffer, pQueryHeader, pQueryQuestion);
|
||||
|
||||
sock.sendto(addr, port, buffer, nbrBytes);
|
||||
});
|
||||
|
||||
INFO("DNS Server", "Listening on port %d\n", port);
|
||||
}
|
6
SOURCE/UNIKERNEL/DNS/vm.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"net" : [
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"},
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"}
|
||||
]
|
||||
}
|
42
SOURCE/UNIKERNEL/Firewall/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
|
||||
# IncludeOS install location
|
||||
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
|
||||
set(ENV{INCLUDEOS_PREFIX} /usr/local)
|
||||
endif()
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
|
||||
project (Firewall)
|
||||
|
||||
# Human-readable name of your service
|
||||
set(SERVICE_NAME "CETIC Firewall Service")
|
||||
|
||||
# Name of your service binary
|
||||
set(BINARY "Firewall")
|
||||
|
||||
# Source files to be linked with OS library parts to form bootable image
|
||||
set(SOURCES
|
||||
service.cpp # ...add more here
|
||||
)
|
||||
|
||||
# To add your own include paths:
|
||||
# set(LOCAL_INCLUDES ".")
|
||||
|
||||
# DRIVERS / PLUGINS:
|
||||
|
||||
if ("$ENV{PLATFORM}" STREQUAL "x86_solo5")
|
||||
set(DRIVERS
|
||||
solo5net
|
||||
)
|
||||
else()
|
||||
set(DRIVERS
|
||||
virtionet # Virtio networking
|
||||
# virtioblock # Virtio block device
|
||||
# ... Others from src/drivers
|
||||
)
|
||||
endif()
|
||||
|
||||
set(PLUGINS
|
||||
)
|
||||
|
||||
# include service build script
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
|
7
SOURCE/UNIKERNEL/Firewall/cmake_build.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
pushd build
|
||||
cmake ..
|
||||
make
|
||||
popd
|
41
SOURCE/UNIKERNEL/Firewall/nacl.txt
Normal file
@ -0,0 +1,41 @@
|
||||
Iface outside {
|
||||
address: 192.168.100.254,
|
||||
netmask: 255.255.255.0,
|
||||
index: 0
|
||||
}
|
||||
|
||||
Iface inside {
|
||||
address: 192.168.101.3,
|
||||
netmask: 255.255.255.248,
|
||||
gateway: 192.168.101.2,
|
||||
index: 1
|
||||
}
|
||||
|
||||
Gateway routing {
|
||||
forward: firewallChain,
|
||||
outside_route: {
|
||||
net: 192.168.100.0,
|
||||
netmask: 255.255.255.0,
|
||||
iface: outside
|
||||
},
|
||||
firewall_to_router_route: {
|
||||
net: 192.168.101.0,
|
||||
netmask: 255.255.255.248,
|
||||
iface: inside
|
||||
},
|
||||
inside_route: {
|
||||
net: 10.0.0.0,
|
||||
netmask: 255.255.255.0,
|
||||
iface: inside
|
||||
}
|
||||
}
|
||||
|
||||
Filter::IP firewallChain {
|
||||
Filter::ICMP {
|
||||
if (icmp.type == echo-request) {
|
||||
log("Dropped ping from ", ip.saddr, " to ", ip.daddr, "\n")
|
||||
drop
|
||||
}
|
||||
}
|
||||
accept
|
||||
}
|
6
SOURCE/UNIKERNEL/Firewall/service.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include <os>
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
printf("IncludeOS firewall booted up");
|
||||
}
|
6
SOURCE/UNIKERNEL/Firewall/vm.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"net" : [
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"},
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"}
|
||||
]
|
||||
}
|
42
SOURCE/UNIKERNEL/Router/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
|
||||
# IncludeOS install location
|
||||
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
|
||||
set(ENV{INCLUDEOS_PREFIX} /usr/local)
|
||||
endif()
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
|
||||
project (Router)
|
||||
|
||||
# Human-readable name of your service
|
||||
set(SERVICE_NAME "CETIC Router Service")
|
||||
|
||||
# Name of your service binary
|
||||
set(BINARY "Router")
|
||||
|
||||
# Source files to be linked with OS library parts to form bootable image
|
||||
set(SOURCES
|
||||
service.cpp # ...add more here
|
||||
)
|
||||
|
||||
# To add your own include paths:
|
||||
# set(LOCAL_INCLUDES ".")
|
||||
|
||||
# DRIVERS / PLUGINS:
|
||||
|
||||
if ("$ENV{PLATFORM}" STREQUAL "x86_solo5")
|
||||
set(DRIVERS
|
||||
solo5net
|
||||
)
|
||||
else()
|
||||
set(DRIVERS
|
||||
virtionet # Virtio networking
|
||||
# virtioblock # Virtio block device
|
||||
# ... Others from src/drivers
|
||||
)
|
||||
endif()
|
||||
|
||||
set(PLUGINS
|
||||
)
|
||||
|
||||
# include service build script
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
|
7
SOURCE/UNIKERNEL/Router/cmake_build.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
pushd build
|
||||
cmake ..
|
||||
make
|
||||
popd
|
38
SOURCE/UNIKERNEL/Router/config.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"net" : [
|
||||
{
|
||||
"iface": 0,
|
||||
"config": "static",
|
||||
"address": "10.0.0.254",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "10.0.0.254"
|
||||
},
|
||||
{
|
||||
"iface": 1,
|
||||
"config": "static",
|
||||
"address": "192.168.101.2",
|
||||
"netmask": "255.255.255.248",
|
||||
"gateway": "192.168.101.3"
|
||||
}
|
||||
|
||||
],
|
||||
"router" : [
|
||||
[
|
||||
{
|
||||
"address": "10.0.0.0",
|
||||
"netmask": "255.255.255.0",
|
||||
"iface" : 0
|
||||
},
|
||||
{
|
||||
"address": "192.168.101.0",
|
||||
"netmask": "255.255.255.248",
|
||||
"iface" : 1
|
||||
},
|
||||
{
|
||||
"address": "0.0.0.0",
|
||||
"netmask": "0.0.0.0",
|
||||
"iface" : 1
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
17
SOURCE/UNIKERNEL/Router/service.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This code is copied from the IncludeOS Router example.
|
||||
*/
|
||||
|
||||
#include <service>
|
||||
#include <net/router>
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
auto& router = net::get_router();
|
||||
|
||||
auto& eth0 = net::Super_stack::get<net::IP4>(0);
|
||||
auto& eth1 = net::Super_stack::get<net::IP4>(1);
|
||||
|
||||
eth0.set_forward_delg(router.forward_delg());
|
||||
eth1.set_forward_delg(router.forward_delg());
|
||||
}
|
6
SOURCE/UNIKERNEL/Router/vm.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"net" : [
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"},
|
||||
{"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"}
|
||||
]
|
||||
}
|
42
SOURCE/UNIKERNEL/WebServer/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 2.8.9)
|
||||
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
|
||||
set(ENV{INCLUDEOS_PREFIX} /usr/local)
|
||||
endif()
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
|
||||
|
||||
project (WebServer)
|
||||
|
||||
# Human-readable name of your service
|
||||
set(SERVICE_NAME "CETIC Unikernel Web Server")
|
||||
|
||||
# Name of your service binary
|
||||
set(BINARY "WebServer")
|
||||
|
||||
# Source files to be linked with OS library parts to form bootable image
|
||||
set(SOURCES
|
||||
service.cpp # ...add more here
|
||||
)
|
||||
|
||||
# To add your own include paths:
|
||||
# set(LOCAL_INCLUDES ".")
|
||||
|
||||
# DRIVERS / PLUGINS:
|
||||
set(DRIVERS
|
||||
virtionet # Virtio networking
|
||||
)
|
||||
|
||||
set(PLUGINS
|
||||
autoconf
|
||||
)
|
||||
|
||||
# STATIC LIBRARIES:
|
||||
set(LIBRARIES
|
||||
# path to full library
|
||||
)
|
||||
|
||||
|
||||
# include service build script
|
||||
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
|
||||
|
||||
# Create in-memory filesystem from folder
|
||||
diskbuilder(disk)
|
7
SOURCE/UNIKERNEL/WebServer/cmake_build.sh
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build
|
||||
pushd build
|
||||
cmake ..
|
||||
make
|
||||
popd
|
13
SOURCE/UNIKERNEL/WebServer/config.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"net": [
|
||||
{
|
||||
"iface": 0,
|
||||
"config": "static",
|
||||
"address": "10.0.0.5",
|
||||
"netmask": "255.255.255.0",
|
||||
"gateway": "10.0.0.254"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
15
SOURCE/UNIKERNEL/WebServer/disk/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>CETIC Internship Unikernel Web Page</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu:500,300" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="font-family: Arial, sans-serif">
|
||||
CETIC Internship Unikernel Web Page
|
||||
</h1>
|
||||
<hr />
|
||||
<p>This is the first web server spawn from a unikernel during the CETIC Intership 2017-18</p>
|
||||
</body>
|
||||
</html>
|
47
SOURCE/UNIKERNEL/WebServer/service.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This code is adapted from the IncludeOS Acorn web server example.
|
||||
*/
|
||||
|
||||
#include <service>
|
||||
#include <net/inet4>
|
||||
#include <net/http/server.hpp>
|
||||
#include <memdisk>
|
||||
std::unique_ptr<http::Server> server;
|
||||
|
||||
void Service::start()
|
||||
{
|
||||
// Retreive the stack (configured from outside)
|
||||
auto& inet = net::Inet4::stack<0>();
|
||||
Expects(inet.is_configured());
|
||||
|
||||
// Init the memdisk
|
||||
auto& disk = fs::memdisk();
|
||||
disk.init_fs([] (auto err, auto&) {
|
||||
Expects(not err);
|
||||
});
|
||||
// Retreive the HTML page from the disk
|
||||
auto file = disk.fs().read_file("/index.html");
|
||||
Expects(file.is_valid());
|
||||
net::tcp::buffer_t html(
|
||||
new std::vector<uint8_t> (file.data(), file.data() + file.size()));
|
||||
|
||||
// Create a HTTP Server and setup request handling
|
||||
server = std::make_unique<http::Server>(inet.tcp());
|
||||
server->on_request([html] (auto req, auto rw)
|
||||
{
|
||||
// We only support get
|
||||
if(req->method() != http::GET) {
|
||||
rw->write_header(http::Not_Found);
|
||||
return;
|
||||
}
|
||||
// Serve HTML on /
|
||||
if(req->uri() == "/") {
|
||||
rw->write(html);
|
||||
} else {
|
||||
rw->write_header(http::Not_Found);
|
||||
}
|
||||
});
|
||||
|
||||
// Start listening on port 80
|
||||
server->listen(80);
|
||||
}
|
10
SOURCE/UNIKERNEL/external.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<network>
|
||||
<name>external</name>
|
||||
<bridge name='virbr11' stp='on' delay='0'/>
|
||||
<domain name='external'/>
|
||||
<ip address='192.168.100.0' netmask='255.255.255.0'>
|
||||
<dhcp>
|
||||
<range start='192.168.100.100' end='192.168.100.200'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|
6
SOURCE/UNIKERNEL/firewall.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<network>
|
||||
<name>firewall</name>
|
||||
<bridge name='virbr12' stp='on' delay='0'/>
|
||||
<domain name='firewall'/>
|
||||
<ip address='192.168.101.1' netmask='255.255.255.248'/>
|
||||
</network>
|
10
SOURCE/UNIKERNEL/internal.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<network>
|
||||
<name>internal</name>
|
||||
<bridge name='virbr10' stp='on' delay='0'/>
|
||||
<domain name='internal'/>
|
||||
<ip address='10.0.0.1' netmask='255.255.255.0'>
|
||||
<dhcp>
|
||||
<range start='10.0.0.100' end='10.0.0.200'/>
|
||||
</dhcp>
|
||||
</ip>
|
||||
</network>
|