diff --git a/docs/quantification.md b/docs/quantification.md
new file mode 100644
index 0000000..92060cc
--- /dev/null
+++ b/docs/quantification.md
@@ -0,0 +1,47 @@
+# Quantification #
+This page describes LINC's resources consumption.
+
+## Adding resources  ##
+To add ports and logical switches to the LINC instance you have to edit `rel/files/sys.config` file. You will there comments on how to do this.
+
+## Memory consumptions ##
+LINC has three major components that make up memory consumption:
+* ports and logical switches,
+* flow entries.
+
+### Average values ###
+On average a LINC port consumes ~ 11 kb.
+Memory consumed by logical switches is not linear. For example a logical switch with 20 ports consumes:
+* ~ 1200 kb if we have 10 such switches
+* ~ 2200 kb if we have 20 such switches
+* ~ 5100 kb if we have 30 such switches
+
+### Measuring ###
+There is a script `scripts/mem_usage_test` that helps with estimating memory requirements.
+
+To measure how much memory one port will take use it as follows:
+```bash
+./scripts/mem_usage_test ports <interval> <max_ports_number>
+```
+In the test amount of ports indicated by the `interval` will be added to the LINC instance in each iteration until reaching the `max_port_number`. The script produces output file `ports.test` that has three columns:
+* number of ports in the LINC instance,
+* memory consumed by the LINC instance,
+* memory consumed by this LINC instance minus the amount of memory consumed in the previous test.
+At the bottom of the file there's a summary line.
+
+To memory how much memory one logical switch witch fixed number of ports invoke the script as follows:
+
+```bash
+./scripts/mem_usage_test switches <ports_per_switch> <max_switches>
+```
+In this test an additional logical switch will be added to the LINC instance in each iteration until reaching the `max_switches`. The test produces an output file that has three columns:
+* number of logical switches started in a LINC instance,
+* memory consumed by the LINC instance,
+* memory consumed by this LINC instance minus the amount of memory consumed in the previous test.
+At the bottom of the file there's a summary line.
+
+## Tuning Erlang VM  ##
+Each logical switch allocates approximately 280 ETS tables. To change this value you have to edit `rel/files/vm.args` file and change the value of ERL_MAX_ETS_TABLES. You find details in the file.
+
+## TODO  ##
+Measure flow entries.
diff --git a/rel/files/sys.config b/rel/files/sys.config
index da637e8..ef1881c 100644
--- a/rel/files/sys.config
+++ b/rel/files/sys.config
@@ -41,6 +41,11 @@
    %% Configuration of the logical switches.
    {logical_switches,
     [
+     %% To add a new logical switch add a new entry to this list similar to
+     %% the one below. Keep in mind that:
+     %% a. logical switches need uniquie interger id (second element
+     %%    of the tuple),
+     %% b. you have to assign ports to the logical switch manually.
      {switch, 0,
       [
        %% Configuration of switch backend implementation used by ofs_logic
diff --git a/scripts/config_generator.erl b/scripts/config_generator.erl
new file mode 100644
index 0000000..02b7725
--- /dev/null
+++ b/scripts/config_generator.erl
@@ -0,0 +1,76 @@
+-module(config_generator).
+
+-export([generate/2]).
+
+-spec generate(PortsCnt :: non_neg_integer(),
+      LogicalSwitchesCnt :: non_neg_integer()) ->
+                      Result :: term().
+generate(PortsCnt, LogicalSwitchesCnt) ->
+    [
+     {linc,
+      [
+       {of_config, enabled},
+       {capable_switch_ports, generate_ports(PortsCnt * LogicalSwitchesCnt)},
+       {capable_switch_queues, []},
+       {logical_switches,
+        generate_logical_switches(PortsCnt, LogicalSwitchesCnt)}
+      ]},
+     {enetconf,
+      [
+       {capabilities, [{base, {1, 1}},
+                       {startup, {1, 0}},
+                       {'writable-running', {1, 0}}]},
+       {callback_module, linc_ofconfig},
+       {sshd_ip, any},
+       {sshd_port, 1830},
+       {sshd_user_passwords,
+        [
+         {"linc", "linc"}
+        ]}
+      ]},
+     {lager,
+      [
+       {handlers,
+        [
+         {lager_console_backend, info},
+         {lager_file_backend,
+          [
+           {"log/error.log", error, 10485760, "$D0", 5},
+           {"log/console.log", info, 10485760, "$D0", 5}
+          ]}
+        ]}
+      ]},
+     {sasl,
+      [
+       {sasl_error_logger, {file, "log/sasl-error.log"}},
+       {errlog_type, error},
+       {error_logger_mf_dir, "log/sasl"},      % Log directory
+       {error_logger_mf_maxbytes, 10485760},   % 10 MB max file size
+       {error_logger_mf_maxfiles, 5}           % 5 files max
+      ]},
+     {sync,
+      [
+       {excluded_modules, [procket]}
+      ]}
+    ].
+
+generate_ports(PortsCnt) ->
+    [{port, N, [{interface, "tap" ++ integer_to_list(N)}]}
+     || N <- lists:seq(1, PortsCnt)].
+
+generate_logical_switches(_, 0) ->
+    [];
+generate_logical_switches(PortsCnt, LogicalSwitchesCnt) ->
+    [
+     {switch, N,
+      [
+       {backend, linc_us4},
+       {controllers,[]},
+       {queues_status, disabled},
+       {ports, generate_logical_switch_ports(PortsCnt, (N - 1) * PortsCnt + 1)}
+      ]}
+     || N <- lists:seq(1, LogicalSwitchesCnt)].
+
+generate_logical_switch_ports(PortsCnt, StartPortNo) ->
+    [{port, N, {queues, []}} || N <- lists:seq(StartPortNo,
+                                               StartPortNo + PortsCnt - 1)].
diff --git a/scripts/memory_usage_test b/scripts/memory_usage_test
new file mode 100755
index 0000000..4a0dab2
--- /dev/null
+++ b/scripts/memory_usage_test
@@ -0,0 +1,240 @@
+#!/usr/bin/env escript
+%%! -sname linc_tester@localhost
+
+-define(CONFIG_FILE, "tmp.sys.config").
+-define(COOKIE, cookie).
+-define(LINC_NODE_NAME_BASE, "linc_under_test").
+-define(MNESIA_DIR_BASE, "Mnesia." ++ ?LINC_NODE_NAME_BASE).
+-define(LOG_DIR, "log/").
+
+main([Type, Arg1, Arg2]) ->
+    process_flag(trap_exit, true),
+    compile:file("config_generator.erl"),
+    register(linc_tester_proc, self()),
+    erlang:set_cookie(node(), ?COOKIE),
+    case Type of
+        "ports" ->
+            increasing_ports(get_linc_node_name(),
+                             0,
+                             list_to_integer(Arg1),
+                             list_to_integer(Arg2),
+                             {0, []});
+        "switches" ->
+            increasing_switches(get_linc_node_name(),
+                                list_to_integer(Arg1),
+                                0,
+                                list_to_integer(Arg2), {0, 0});
+        _ ->
+            io:format("Unknown test.~n"),
+            usage()
+    end,
+    clean_up();
+main(_) ->
+    usage().
+
+usage() ->
+    io:format("~s [ports <interval> <max ports>"
+              ++ " | switches <ports per switch> <max switches>]~n",
+              [escript:script_name()]).
+
+
+
+increasing_switches(_ , Ports, Switches, MaxSwitches, {_, MemPerSwitchAcc})
+  when Switches > MaxSwitches ->
+    file:write_file(result_file(switches),
+                    io_lib:fwrite("On avarage a logical switch with ~p ports"
+                                  ++ " consumes ~p kb.~n",
+                                  [Ports, MemPerSwitchAcc/(Switches - 1)]),
+                    [append]);
+increasing_switches(LincNode, Ports, Switches, MaxSwitches, Data) ->
+    ok = generate_config(Ports, Switches),
+    LincNodePort = start_linc_node(LincNode),
+    Mem = test_memory(LincNode),
+    ok = stop_linc_node(LincNode, LincNodePort),
+    NewData = case Switches of
+                  0 ->
+                      write_result(switches, Switches, Mem, undef),
+                      {Mem, 0};
+                  _ ->
+                      {LastMem, MemPerSwitchAcc} = Data,
+                      Diff = Mem - LastMem,
+                      write_result(switches, Switches, Mem, Diff),
+                      {Mem, MemPerSwitchAcc + Diff}
+              end,
+    increasing_switches(
+      get_linc_node_name(), Ports, Switches + 1, MaxSwitches, NewData).
+
+increasing_ports(LincNode, PortsCnt, Interval, MaxPortsCnt, TestData)
+  when PortsCnt > MaxPortsCnt ->
+    increasing_ports(
+      LincNode,
+      MaxPortsCnt,
+      MaxPortsCnt rem Interval,
+      MaxPortsCnt,
+      TestData);
+increasing_ports(LincNode, PortsCnt, Interval, MaxPortsCnt, TestData) ->
+    ok  = generate_config(PortsCnt, 1),
+    LincNodePort = start_linc_node(LincNode),
+    NewTestData = case PortsCnt of
+                      0 ->
+                          Mem = test_memory(LincNode),
+                          write_result(ports, PortsCnt, Mem, undef),
+                          {Mem, []};
+                      _ ->
+                          Mem = test_memory(LincNode),
+                          {LastMem, PortAvgMem} = TestData,
+                          write_result(ports, PortsCnt, Mem,
+                                       Diff = Mem - LastMem),
+                          {Mem, [Diff div Interval | PortAvgMem]}
+                  end,
+    ok = stop_linc_node(LincNode, LincNodePort),
+    case PortsCnt == MaxPortsCnt of
+        true ->
+            {_, PortAvgMem2} = NewTestData,
+            file:write_file(result_file(ports),
+                            io_lib:fwrite("On average a port consumes ~p kb.~n",
+                                          [lists:foldl(fun(X, Acc) ->
+                                                               X + Acc end,
+                                                       0, PortAvgMem2)
+                                           / length(PortAvgMem2)]),
+                            [append]);
+        _ ->
+            increasing_ports(get_linc_node_name(),
+                             PortsCnt + Interval,
+                             Interval,
+                             MaxPortsCnt,
+                             NewTestData)
+    end.
+
+test_memory(LincNode) ->
+    Pid = self(),
+    spawn(LincNode, fun() ->
+                            Pid ! {mem_test, erlang:memory(total)}
+                    end),
+    receive
+        {mem_test, Memory} ->
+            io:format("Got memory usage: ~p kb.~n", [Memory]),
+            Memory div 1024
+    after
+        5000 ->
+            io:format("No response from ~p.~n", [LincNode]),
+            0
+    end.
+
+start_linc_node(LincNode) ->
+    Cmd = "erl -env ERL_MAX_ETS_TABLES 6000 "
+        ++ code_paths()
+        ++ " -config " ++ ?CONFIG_FILE
+        ++ " -setcookie " ++ atom_to_list(?COOKIE)
+        ++ " -sname " ++ atom_to_list(LincNode)
+        ++ " -detached"
+        ++ " -eval \""
+        ++ eval(Msg = hello)
+        ++ "\"",
+    LincNodePort = erlang:open_port({spawn, Cmd}, []),
+    io:format("Waiting for test node to connect..."),
+    receive
+        Msg ->
+            io:format("connected~n")
+    after
+        20000 ->
+            io:format("Error while starting test node~n")
+    end,
+    LincNodePort.
+
+stop_linc_node(LincNode, LincNodePort) ->
+    %% port_close(LincNodePort).
+    spawn(LincNode, fun() ->
+                            init:stop()
+                    end),
+    receive
+        {'EXIT', LincNodePort, normal} ->
+            ok
+    after
+        10000 ->
+            io:format("LINC node: not exitted~n"),
+            error
+    end.
+
+code_paths() ->
+    Paths = lists:foldl(fun(Path, Acc) ->
+                                Acc ++ filelib:wildcard(Path)
+                        end, [], ["../apps/*/ebin", "../deps/*/ebin"]),
+    lists:foldl(fun(Path, Acc) ->
+                        Acc ++ " -pa " ++ Path
+                end, [], Paths).
+
+eval(Msg) ->
+    {registered_name, ProcName} = process_info(self(), registered_name),
+    "lists:map(fun application:start/1,
+                                       [kernel, stdlib, public_key, crypto, ssl,
+                                        compiler, syntax_tools, runtime_tools,
+                                        xmerl, mnesia, lager, linc]),"
+        ++ "true = net_kernel:connect_node(" ++ atom_to_list(node()) ++ "),"
+        ++ "{" ++ atom_to_list(ProcName) ++ "," ++ atom_to_list(node()) ++ "}"
+        ++ " ! " ++ atom_to_list(Msg) ++ ".".
+
+
+ports_result_header() ->
+    "Ports | Memory | Difference\n".
+
+switches_result_header() ->
+    "Switches | Memory | Difference\n".
+
+result_line(0, Mem, _) ->
+    "0 " ++ integer_to_list(Mem) ++ " none\n";
+result_line(PortsCnt, Mem, Diff) ->
+    integer_to_list(PortsCnt)
+        ++ " "
+        ++ integer_to_list(Mem)
+        ++ " "
+        ++ integer_to_list(Diff)
+        ++ "\n".
+
+generate_config(Ports, Switches) ->
+    file:write_file(?CONFIG_FILE,
+                         io_lib:fwrite(
+                           "~p.~n",
+                           [config_generator:generate(Ports, Switches)])).
+
+write_result(Type, Cnt, Mem, Diff) ->
+    Content = case Cnt of
+                  0 ->
+                      result_header(Type) ++ result_line(0, Mem, undef);
+                  _ ->
+                      result_line(Cnt, Mem, Diff)
+              end,
+    ok = file:write_file(result_file(Type), Content, case Cnt of
+                                                    0 -> [write];
+                                                    _ -> [append]
+                                                end).
+result_file(Type) ->
+    case Type of
+        ports -> "ports.test";
+        switches -> "switches.test"
+    end.
+
+result_header(Type) ->
+    case Type of
+        ports ->
+            ports_result_header();
+        switches ->
+            switches_result_header()
+    end.
+
+get_linc_node_name() ->
+    list_to_atom(?LINC_NODE_NAME_BASE
+                 ++ integer_to_list(element(3, now()))
+                 ++ "@localhost").
+
+clean_up() ->
+    file:delete(?CONFIG_FILE),
+    lists:foreach(fun(Dir) ->
+                          ok = delete_directory(Dir)
+                  end, [ ?LOG_DIR | filelib:wildcard(?MNESIA_DIR_BASE ++ "*")]).
+
+delete_directory(Dir) ->
+    lists:foreach(fun(File) ->
+                          ok = file:delete(File)
+                  end, filelib:wildcard(Dir ++ "/*")),
+    ok = file:del_dir(Dir).