-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
72e7a94
commit c61d63c
Showing
10 changed files
with
436 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.PHONY: compile | ||
|
||
compile: | ||
./rebar get-deps compile escriptize |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
] | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, []} | ||
]}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]}). | ||
|
||
|
Oops, something went wrong.