Skip to content

Commit

Permalink
moved to new repo
Browse files Browse the repository at this point in the history
  • Loading branch information
ruanpienaar committed Sep 17, 2014
1 parent 72e7a94 commit c61d63c
Show file tree
Hide file tree
Showing 10 changed files with 436 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.PHONY: compile

compile:
./rebar get-deps compile escriptize
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
LINC-config-generator
=====================
# LINC Configuration generator

Code that generates the LINC configuration from the JSON topology files

Utility that takes a JSON topology description file and generates a `sys.config` configuration file for the [LINC Switch](http://github.com/FlowForwarding/LINC-Switch).

## Usage

Compile:

```
$ make
```

run the config generator:

```
$ ./config_generator $PWD/json_example.json $PWD/sys.config.template localhost 4343
```

This will generate a `sys.config` file in $PWD.
2 changes: 2 additions & 0 deletions go.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
make && ./config_generator $PWD/json_example.json $PWD/sys.config.template localhost 4343 && cat sys.config
88 changes: 88 additions & 0 deletions json_example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"comment": "Multilayer topology description and configuration",
"restrictLinks": false,
"restrictSwitches": false,

"switchConfig": [
{
"allowed": true,
"latitude": 80.8,
"longitude": 90.1,
"name": "Dallas-W1",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"numRegen": 2
},
"type": "Roadm"
},
{
"allowed": true,
"latitude": 80.8,
"longitude": 90.1,
"name": "NYC-W10",
"nodeDpid": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"numRegen": 3
},
"type": "Roadm"
}
],

"linkConfig": [
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:02",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
"params": {
"distKms": 5000,
"nodeName1": "Dallas-W1",
"nodeName2": "NYC-W10",
"numWaves": 80,
"port1": 20,
"port2": 21
},
"type": "wdmLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:00",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
"params": {
"nodeName1": "Dallas-R1",
"nodeName2": "Dallas-W1",
"port1": 33,
"port2": 10
},
"type": "pktOptLink"
},
{
"allowed": true,
"nodeDpid1": "00:00:ff:ff:ff:ff:ff:00",
"nodeDpid2": "00:00:ff:ff:ff:ff:ff:01",
"params": {
"port1": 6,
"port2": 1
},
"type": "pktLink"
}
],

"opticalReachabilty": [
[
"Dallas-W1",
"NYC-W10"
],
[
"NYC-W10",
"Dallas-W1"
],
[
"Dallas-W2",
"SFO-W3"
],
[
"SFO-W3",
"Dallas-W2"
]
]
}
Binary file added rebar
Binary file not shown.
9 changes: 9 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{deps,
[{jsx, ".*",
{git, "https://github.com/talentdeficit/jsx.git", {tag, "v2.1.1"}}}]}.

{escript_name, "config_generator"}.
{escript_incl_apps, [jsx]}.
{escript_shebang, "#!/usr/bin/env escript\n"}.
{escript_comment, "%%\n"}.
{escript_emu_args, "%%! -pa deps/*/ebin\n"}.
12 changes: 12 additions & 0 deletions src/config_generator.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{application, config_generator,
[
{description, ""},
{vsn, "1"},
{registered, []},
{applications, [
kernel,
stdlib
]},
{mod, { config_generator, []}},
{env, []}
]}.
231 changes: 231 additions & 0 deletions src/config_generator.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
%%%=============================================================================
%%% @author Ramon Lastres <[email protected]>
%%% @doc Code that parses a config file in JSON format and creates a LINC switch
%%% Erlang term part of the sys.config file
%%% Of course it needs to have JSX in the path to work!
%%% @end
%%%=============================================================================
-module(config_generator).

-include_lib("eunit/include/eunit.hrl").

-export([main/1,
parse/4

]).

%%%=============================================================================
%%% Api functions
%%%=============================================================================

%%%=============================================================================
%%% @doc Takes a file name and returns the 'linc' element that is supposed to
%%% be part of the sys.config file
%%% @end
%%%=============================================================================

main(Args) ->
parse(Args).

parse([Filename, FileTemplate, ControllerIP, Port]) ->
parse(Filename, FileTemplate, ControllerIP, Port).

-spec parse(Filename :: file:name_all(),
FileTemplate :: file:name_all(),
ControllerIP :: string(),
Port :: integer()) -> {linc, [tuple()]}.
parse(Filename, FileTemplate, ControllerIP, Port) ->
{ok, Binary} = file:read_file(Filename),
{ok, [Config]} = file:consult(FileTemplate),
Json = jsx:decode(Binary),
SwitchConfig = proplists:get_value(<<"switchConfig">>, Json),
LinkConfig = proplists:get_value(<<"linkConfig">>, Json),
Linc = generate_linc_element(SwitchConfig, LinkConfig, ControllerIP, Port),
FinalConfig = [Linc] ++ Config,
ok = file:write_file("sys.config",io_lib:fwrite("~p.\n", [FinalConfig])).


%%%=============================================================================
%%% Internal Functions
%%%=============================================================================

packet2optical_links(LinkConfig) ->
lists:filter(fun(X) -> lists:member({<<"type">>, <<"pktOptLink">>}, X) end,
LinkConfig).

optical_links(LinkConfig) ->
lists:filter(fun(X) -> lists:member({<<"type">>, <<"wdmLink">>}, X) end,
LinkConfig).

get_logical_switches(SwitchConfig, LinkConfig, ControllerIP, Port) ->
Dpids = get_switches_dpids(SwitchConfig),
DpidsToNumber = get_dpids2number(SwitchConfig),
OpticalLinks = get_optical_links(LinkConfig, SwitchConfig),
OpticalLinkPorts = get_p2o_links_ports(LinkConfig, SwitchConfig),
lists:map(fun(X) -> generate_switch_element(X, OpticalLinks,
OpticalLinkPorts, ControllerIP,
Port, DpidsToNumber)
end, Dpids).

get_switches_dpids(SwitchConfig) ->
lists:map(fun(X) -> proplists:get_value(<<"nodeDpid">>, X) end,
SwitchConfig).

get_dpids2number(SwitchConfig) ->
Dpids = get_switches_dpids(SwitchConfig),
lists:zip(Dpids, lists:seq(1, length(Dpids))).

%We want the optical port and dpid.
parse_packet2optical_link(P2OLink, SwitchConfig) ->
Dpids = get_switches_dpids(SwitchConfig),
DpidsToNumber = get_dpids2number(SwitchConfig),
Params = proplists:get_value(<<"params">>, P2OLink),
Dpid1 = proplists:get_value(<<"nodeDpid1">>, P2OLink),
Dpid2 = proplists:get_value(<<"nodeDpid2">>, P2OLink),
case lists:member(Dpid1, Dpids) of
true ->
{proplists:get_value(Dpid1, DpidsToNumber),
proplists:get_value(<<"port1">>, Params)};
_ ->
{proplists:get_value(Dpid2, DpidsToNumber),
proplists:get_value(<<"port2">>, Params)}
end.

parse_optical_link(OpticalLink, DpidsToNumber) ->
Params = proplists:get_value(<<"params">>, OpticalLink),
[
{proplists:get_value(proplists:get_value(<<"nodeDpid1">>, OpticalLink),
DpidsToNumber),
proplists:get_value(<<"port1">>, Params)},
{proplists:get_value(proplists:get_value(<<"nodeDpid2">>, OpticalLink),
DpidsToNumber),
proplists:get_value(<<"port2">>, Params)}
].

get_p2o_links_ports(LinkConfig, SwitchConfig) ->
lists:map(fun(X) -> parse_packet2optical_link(X, SwitchConfig) end,
packet2optical_links(LinkConfig)).

get_optical_links(LinkConfig, SwitchConfig) ->
DpidsToNumber = get_dpids2number(SwitchConfig),
lists:map(fun(X) -> parse_optical_link(X, DpidsToNumber) end,
optical_links(LinkConfig)).

get_optical_link_pairs(LinkConfig, SwitchConfig) ->
DpidsToNumber = get_dpids2number(SwitchConfig),
lists:map(fun(X) ->
list_to_tuple(parse_optical_link(X, DpidsToNumber))
end,optical_links(LinkConfig)).

optical_port_element([{_SwitchNum1, PortNumber1},
{_SwitchNum2, PortNumber2}]) ->
[{port, PortNumber1, [{interface, "dummy"}, {type, optical}]},
{port, PortNumber2, [{interface, "dummy"}, {type, optical}]}].

p2o_port_element({_Dpid, PortNumber}) ->
{port, PortNumber, [{interface, "tap" ++ integer_to_list(PortNumber)}]}.

get_switch_ports(SwitchDpid, OpticalLinks, P2OLinkPorts) ->
List = lists:flatten(OpticalLinks ++ P2OLinkPorts),
[Port || {Dpid, Port} <- List, Dpid == SwitchDpid].

get_capable_switch_ports(LinkConfig, SwitchConfig) ->
List = lists:flatten(lists:map(fun optical_port_element/1,
get_optical_links(LinkConfig, SwitchConfig)) ++
lists:map(fun p2o_port_element/1,
get_p2o_links_ports(LinkConfig, SwitchConfig))),
lists:usort(List).

generate_switch_element(SwitchDpid, OpticalLinks, OpticalLinkPorts,
ControllerIP, Port, DpidsToNumber) ->
Ports = lists:usort(
get_switch_ports(proplists:get_value(SwitchDpid, DpidsToNumber),
OpticalLinks, OpticalLinkPorts)),
{switch, proplists:get_value(SwitchDpid, DpidsToNumber),
[{backend,linc_us4_oe},
{datapath_id, binary_to_list(SwitchDpid)},
{controllers,[{"Switch0-Controller", ControllerIP, list_to_integer(Port), tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports, lists:map(fun port_queue_element/1, Ports)}]}.

port_queue_element(PortNumber) ->
{port, PortNumber, {queues, []}}.

generate_linc_element(SwitchConfig, LinkConfig, ControllerIP, Port) ->
{linc,
[{of_config, disabled},
{software_desc, <<"LINC-OE OpenFlow Software Switch 1.1">>},
{capable_switch_ports, get_capable_switch_ports(LinkConfig,
SwitchConfig)},
{capable_switch_queues, []},
{optical_links, get_optical_link_pairs(LinkConfig, SwitchConfig)},
{logical_switches, get_logical_switches(SwitchConfig, LinkConfig,
ControllerIP, Port)}]}.

generator_test() ->
file:copy("sys.config","sys.config."++integer_to_list(
calendar:datetime_to_gregorian_seconds(calendar:now_to_datetime(now()))
)),
io:format("",[]),
ok = main([os:getenv("PWD")++"/json_example.json",
os:getenv("PWD")++"/sys.config.template",
"localhost",
"4343"]),
Expect = {ok,[[{linc,
[{of_config,disabled},
{software_desc,<<"LINC-OE OpenFlow Software Switch 1.1">>},
{capable_switch_ports,
[{port,10,[{interface,"tap10"}]},
{port,20,[{interface,"dummy"},{type,optical}]},
{port,21,[{interface,"dummy"},{type,optical}]}]},
{capable_switch_queues,[]},
{optical_links,[{{1,20},{2,21}}]},
{logical_switches,
[{switch,1,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:02"},
{controllers,[{"Switch0-Controller","localhost",4343,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,[{port,10,{queues,[]}},{port,20,{queues,[]}}]}]},
{switch,2,
[{backend,linc_us4_oe},
{datapath_id,"00:00:ff:ff:ff:ff:ff:03"},
{controllers,[{"Switch0-Controller","localhost",4343,tcp}]},
{controllers_listener,disabled},
{queues_status,disabled},
{ports,[{port,21,{queues,[]}}]}]}]}]},
{epcap,[{verbose,false},{stats_interval,10}]},
{enetconf,
[{capabilities,
[{base,{1,0}},
{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"},
{error_logger_mf_maxbytes,10485760},
{error_logger_mf_maxfiles,5}]},
{sync,[{excluded_modules,[procket]}]}]]},

{ok,[Res]} = file:consult("sys.config"),

%% io:format("optical_links:~p\n",[proplists:get_value(optical_links,proplists:get_value(linc,Res))]),


?assertEqual(Expect,{ok,[Res]}).


Loading

0 comments on commit c61d63c

Please sign in to comment.