havox 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +82 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/config.rb +4 -0
- data/examples/example_3x3.dot +81 -0
- data/examples/example_3x3.hvx +5 -0
- data/exe/havox +107 -0
- data/havox.gemspec +33 -0
- data/lib/havox.rb +51 -0
- data/lib/havox/app/api.rb +57 -0
- data/lib/havox/app/helpers/methods.rb +43 -0
- data/lib/havox/classes/edge.rb +11 -0
- data/lib/havox/classes/modified_policy.rb +44 -0
- data/lib/havox/classes/node.rb +19 -0
- data/lib/havox/classes/policy.rb +68 -0
- data/lib/havox/classes/rib.rb +30 -0
- data/lib/havox/classes/route.rb +82 -0
- data/lib/havox/classes/route_filler.rb +43 -0
- data/lib/havox/classes/rule.rb +74 -0
- data/lib/havox/classes/rule_expander.rb +47 -0
- data/lib/havox/classes/rule_sanitizer.rb +42 -0
- data/lib/havox/classes/topology.rb +75 -0
- data/lib/havox/classes/translator.rb +37 -0
- data/lib/havox/configuration.rb +20 -0
- data/lib/havox/dsl/directive.rb +70 -0
- data/lib/havox/dsl/directive_proxy.rb +36 -0
- data/lib/havox/dsl/examples/routeflow.hvx +12 -0
- data/lib/havox/dsl/network.rb +64 -0
- data/lib/havox/exceptions.rb +21 -0
- data/lib/havox/modules/command.rb +31 -0
- data/lib/havox/modules/field_parser.rb +21 -0
- data/lib/havox/modules/merlin.rb +85 -0
- data/lib/havox/modules/openflow10/ovs/actions.rb +41 -0
- data/lib/havox/modules/openflow10/ovs/matches.rb +35 -0
- data/lib/havox/modules/openflow10/routeflow/actions.rb +45 -0
- data/lib/havox/modules/openflow10/routeflow/matches.rb +44 -0
- data/lib/havox/modules/openflow10/trema/actions.rb +45 -0
- data/lib/havox/modules/openflow10/trema/matches.rb +43 -0
- data/lib/havox/modules/routeflow.rb +50 -0
- data/lib/havox/version.rb +3 -0
- data/lib/merlin/policies/common.mln +9 -0
- data/lib/merlin/policies/defense.mln +5 -0
- data/lib/merlin/policies/max.mln +2 -0
- data/lib/merlin/policies/min.mln +2 -0
- data/lib/merlin/policies/routeflow.mln +8 -0
- data/lib/merlin/policies/test.mln +2 -0
- data/lib/merlin/policies/tetrahedron.mln +8 -0
- data/lib/merlin/policies/tetrahedron.sample.mln +15 -0
- data/lib/merlin/policies/web_balanced.mln +7 -0
- data/lib/merlin/policies/web_unbalanced.mln +2 -0
- data/lib/merlin/topologies/common.dot +63 -0
- data/lib/merlin/topologies/defense.dot +20 -0
- data/lib/merlin/topologies/max.dot +17 -0
- data/lib/merlin/topologies/min.dot +11 -0
- data/lib/merlin/topologies/routeflow.dot +37 -0
- data/lib/merlin/topologies/tetrahedron.dot +39 -0
- data/lib/trema/controllers/main_controller.rb +113 -0
- data/lib/trema/topologies/common_topology.rb +36 -0
- data/lib/trema/topologies/routeflow_topology.rb +21 -0
- data/lib/trema/topologies/tetrahedron_topology.rb +22 -0
- metadata +253 -0
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Havox
|
2
|
+
|
3
|
+
Havox is a rule generator for Autonomous Systems supported by OpenFlow switches. Based on orchestration directives (or instructions) written in its own DSL, Havox generates a set of OpenFlow rules to be installed on the underlying switches.
|
4
|
+
|
5
|
+
As part of a bigger architecture, Havox is designed to run as a web API that receives requests containing the directives, the topology graph description and some parameters for rule formatting. Once the rules are generated, the API responds with a JSON message containing all the rules, each one indicating which OpenFlow switch it should be installed on.
|
6
|
+
|
7
|
+
The mentioned architecture is composed of Havox, [RouteFlow](https://github.com/routeflow/RouteFlow) and [Merlin](https://github.com/merlin-lang/merlin), and currently tested in a [Mininet](https://github.com/mininet/mininet) environment with support of [MiniNext](https://github.com/USC-NSL/miniNExT) implementing Quagga routing engines. RouteFlow requests rules from Havox and therefore is a client, whereas Merlin is a dependency which effectively calculates the paths between the AS exits.
|
8
|
+
|
9
|
+
## Development status
|
10
|
+
|
11
|
+
Havox is still experimental, born from a [master's thesis](http://www2.uniriotec.br/ppgi/banco-de-dissertacoes-ppgi-unirio/ano-2017/havox-uma-arquitetura-para-orquestracao-de-trafego-em-redes-openflow/view), so it is being actively developed and improved. There is yet a lot of new functionalities to come.
|
12
|
+
|
13
|
+
## How it works
|
14
|
+
|
15
|
+
Havox is implemented in Ruby and is strongly based on metaprogramming concepts. The orchestration directives that forms its DSL are methods executed by the Ruby interpreter, having both values and entire blocks of code as parameters. The following code shows some Havox directives:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
topology 'example.dot'
|
19
|
+
associate :rfvmE, :s5
|
20
|
+
|
21
|
+
exit(:s4) { destination_port 80 }
|
22
|
+
|
23
|
+
exit(:s3) {
|
24
|
+
source_ip '200.156.0.0/16'
|
25
|
+
destination_ip '200.20.0.0/16'
|
26
|
+
}
|
27
|
+
```
|
28
|
+
|
29
|
+
The first one, `topology <file_name>` is a topology file definition directive. It takes a string and specifies the topology description file that should be considered, which usually goes together with the directives file in the same request.
|
30
|
+
|
31
|
+
The second, `associate <router_name>, <switch_name>` is the router-switch association directive. It takes a string or a [symbol](https://ruby-doc.org/core-2.4.0/Symbol.html) that specifies the RouteFlow container name that runs the target routing instance and its associated OpenFlow switch name. In this case, it associates the routing container _rfvmE_ to the switch _s5_.
|
32
|
+
|
33
|
+
Next, there are two orchestration directives that instructs the matching flow to leave the network by the indicated switch. The exit directive, `exit(<switch_name>) { <openflow_fields_and_values> }`, takes the switch name as a string or symbol and a block containing the supported OpenFlow fields and their respective matching values, which can be strings or integers depending on the field.
|
34
|
+
|
35
|
+
For example, the first `exit` directive tells that any matching traffic with destination port 80 should leave the domain by the switch _s4_. The second `exit` directive tells that any packet that comes from the network 200.156/16 and heads to the network 200.20/16 must leave the domain by the switch _s3_.
|
36
|
+
|
37
|
+
The topology file is a graph description file written in [DOT language](https://en.wikipedia.org/wiki/DOT_(graph_description_language)) and describes how the network topology is organized. This file is processed by both Havox and its dependency, Merlin. Each node has informations like its name, its internal IP address from one of its interfaces and how it is connected to the other nodes. It is important to know that this IP address is used by Havox to infer the associations between routing containers and switches using OSPF routes. Otherwise, it would be required to manually associate each pair using the association directive described above.
|
38
|
+
|
39
|
+
The exit directives from the request will be transcompiled to Merlin blocks of code, written in a Merlin policy file. This file is sent with the topology file to the Merlin process, where they will be evaluated for paths calculation. The generated raw rules are then post-processed, formatted and outputted by the API.
|
40
|
+
|
41
|
+
More details about the transcompilation, parsing and formatting processes can be found [here](http://www2.uniriotec.br/ppgi/banco-de-dissertacoes-ppgi-unirio/ano-2017/havox-uma-arquitetura-para-orquestracao-de-trafego-em-redes-openflow/view) (master's thesis in brazilian portuguese).
|
42
|
+
|
43
|
+
## Installation
|
44
|
+
|
45
|
+
Install Havox by:
|
46
|
+
|
47
|
+
1. Cloning the repository: `$ git clone https://github.com/rodrigosoares/havox`
|
48
|
+
2. Accessing the directory: `$ cd havox`
|
49
|
+
3. Installing gem dependencies: `$ bin/setup`
|
50
|
+
|
51
|
+
Besides, Havox requires [Merlin](https://github.com/merlin-lang/merlin) and a [modified version of RouteFlow](https://github.com/rodrigosoares/RouteFlow) that implements IP source and VLAN ID matching, subnet mask support and RFHavox module. The latter is an extra RouteFlow module designed to request rules from the remote Havox web API and enqueue them into the RouteFlow IPC system.
|
52
|
+
|
53
|
+
If the tests will be run in a experimental network, [Mininet](https://github.com/mininet/mininet) and [MiniNext](https://github.com/USC-NSL/miniNExT) are also required. Gists containing example Quagga BGP configurations and Mininet topology files can be found [here](https://gist.github.com/rodrigosoares/53ca13f0376ade1fa7b7221328dae3ce).
|
54
|
+
|
55
|
+
It is *strongly recommended* to install Merlin, RouteFlow and Mininet/MiniNext in isolated virtual machines, each. Make sure that all the VMs ping each other successfully. The recommendation is to use [VirtualBox](https://www.virtualbox.org/) with _host-only network_ adapters.
|
56
|
+
|
57
|
+
Setup all projects following their respective installation instructions. If using RouteFlow with Mininet, follow the [instructions](https://github.com/routeflow/RouteFlow/wiki/Tutorial-2:-rftest2) on setting Mininet up with RouteFlow remote controller.
|
58
|
+
|
59
|
+
## Usage
|
60
|
+
|
61
|
+
HVX, MN and RF are the environments running Havox, Mininet and RouteFlow, respectively.
|
62
|
+
|
63
|
+
1. (HVX) Setup Merlin and RouteFlow IPs and etcetera in `config.rb`.
|
64
|
+
2. (HVX) Start Havox API web server: `$ havox`.
|
65
|
+
3. (MN) Start Mininet, pointing its remote controller to the RouteFlow VM.
|
66
|
+
4. (RF) Start RouteFlow: `sudo ./rftest2`.
|
67
|
+
|
68
|
+
If everything runs fine, RouteFlow will send a POST request to Havox, which in turn will log it and respond.
|
69
|
+
|
70
|
+
## Development
|
71
|
+
|
72
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec --format d` to run the tests and read a little documentation about what each component does. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rodrigosoares/havox.
|
77
|
+
|
78
|
+
Be sure to follow [Ruby best practices](https://github.com/bbatsov/ruby-style-guide) and to create a spec test case for each new method, module or component you create.
|
79
|
+
|
80
|
+
## License
|
81
|
+
|
82
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "havox"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/config.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
digraph g1 {
|
2
|
+
h1 [type = host, mac = "00:00:00:00:00:01", ip = "172.31.1.100"];
|
3
|
+
h2 [type = host, mac = "00:00:00:00:00:02", ip = "172.31.2.100"];
|
4
|
+
h3 [type = host, mac = "00:00:00:00:00:03", ip = "172.31.3.100"];
|
5
|
+
h4 [type = host, mac = "00:00:00:00:00:04", ip = "172.31.4.100"];
|
6
|
+
h5 [type = host, mac = "00:00:00:00:00:05", ip = "172.31.5.100"];
|
7
|
+
h6 [type = host, mac = "00:00:00:00:00:06", ip = "172.31.6.100"];
|
8
|
+
h7 [type = host, mac = "00:00:00:00:00:07", ip = "172.31.7.100"];
|
9
|
+
h8 [type = host, mac = "00:00:00:00:00:08", ip = "172.31.8.100"];
|
10
|
+
h9 [type = host, mac = "00:00:00:00:00:09", ip = "172.31.9.100"];
|
11
|
+
|
12
|
+
s1 [type = switch, ip = "172.31.1.1", id = 1];
|
13
|
+
s2 [type = switch, ip = "172.31.2.1", id = 2];
|
14
|
+
s3 [type = switch, ip = "172.31.3.1", id = 3];
|
15
|
+
s4 [type = switch, ip = "172.31.4.1", id = 4];
|
16
|
+
s5 [type = switch, ip = "172.31.5.1", id = 5];
|
17
|
+
s6 [type = switch, ip = "172.31.6.1", id = 6];
|
18
|
+
s7 [type = switch, ip = "172.31.7.1", id = 7];
|
19
|
+
s8 [type = switch, ip = "172.31.8.1", id = 8];
|
20
|
+
s9 [type = switch, ip = "172.31.9.1", id = 9];
|
21
|
+
|
22
|
+
s1 -> h1 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
23
|
+
h1 -> s1 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
24
|
+
|
25
|
+
s2 -> h2 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
26
|
+
h2 -> s2 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
27
|
+
|
28
|
+
s3 -> h3 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
29
|
+
h3 -> s3 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
30
|
+
|
31
|
+
s4 -> h4 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
32
|
+
h4 -> s4 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
33
|
+
|
34
|
+
s5 -> h5 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
35
|
+
h5 -> s5 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
36
|
+
|
37
|
+
s6 -> h6 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
38
|
+
h6 -> s6 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
39
|
+
|
40
|
+
s7 -> h7 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
41
|
+
h7 -> s7 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
42
|
+
|
43
|
+
s8 -> h8 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
44
|
+
h8 -> s8 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
45
|
+
|
46
|
+
s9 -> h9 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
47
|
+
h9 -> s9 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
48
|
+
|
49
|
+
s1 -> s2 [src_port = 2, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
50
|
+
s1 -> s4 [src_port = 3, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
51
|
+
|
52
|
+
s2 -> s1 [src_port = 2, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
53
|
+
s2 -> s3 [src_port = 3, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
54
|
+
s2 -> s5 [src_port = 4, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
55
|
+
|
56
|
+
s3 -> s2 [src_port = 2, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
57
|
+
s3 -> s6 [src_port = 3, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
58
|
+
|
59
|
+
s4 -> s1 [src_port = 2, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
60
|
+
s4 -> s5 [src_port = 4, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
61
|
+
s4 -> s7 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
62
|
+
|
63
|
+
s5 -> s2 [src_port = 1, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
64
|
+
s5 -> s4 [src_port = 2, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
65
|
+
s5 -> s6 [src_port = 3, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
66
|
+
s5 -> s8 [src_port = 4, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
67
|
+
|
68
|
+
s6 -> s3 [src_port = 2, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
69
|
+
s6 -> s5 [src_port = 4, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
70
|
+
s6 -> s9 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
71
|
+
|
72
|
+
s7 -> s4 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
73
|
+
s7 -> s8 [src_port = 2, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
74
|
+
|
75
|
+
s8 -> s5 [src_port = 4, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
76
|
+
s8 -> s7 [src_port = 2, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
77
|
+
s8 -> s9 [src_port = 3, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
78
|
+
|
79
|
+
s9 -> s6 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
80
|
+
s9 -> s8 [src_port = 2, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
81
|
+
}
|
data/exe/havox
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'havox'
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
6
|
+
require_relative '../lib/havox/app/api'
|
7
|
+
|
8
|
+
# Defines command options and parameters.
|
9
|
+
args = OpenStruct.new
|
10
|
+
OptionParser.new do |opt|
|
11
|
+
opt.separator ''
|
12
|
+
opt.separator <<-DESCRIPTION
|
13
|
+
Havox is a rule generator for Autonomous Systems supported by OpenFlow switches.
|
14
|
+
Based on a directives file written in its own DSL and a graph topology file, Havox
|
15
|
+
generates a set of OpenFlow rules to be installed in the underlying switches. Just
|
16
|
+
run the following command to start the Havox API web server:
|
17
|
+
|
18
|
+
havox
|
19
|
+
|
20
|
+
This will run the server on port 4567. It listens for HTTP requests to the /rules
|
21
|
+
route, POST method. The request should contain the directives file, the topology
|
22
|
+
file and a set of configuration parameters that define how the rules should be
|
23
|
+
formatted.
|
24
|
+
|
25
|
+
An alternative way to run Havox is by calling its rules-only mode (prints the rules
|
26
|
+
to the STDOUT) or using the Trema controller (yet experimental). See the options below.
|
27
|
+
DESCRIPTION
|
28
|
+
opt.separator ''
|
29
|
+
|
30
|
+
opt.on('-c', '--trema-topo CONF', 'Trema topology configuration file') { |o| args.trema_topology = o }
|
31
|
+
opt.on('-t', '--merlin-topo TOPO', 'Merlin topology file') { |o| args.merlin_topology = o }
|
32
|
+
opt.on('-p', '--merlin-policy POLICY', 'Merlin policy file') { |o| args.merlin_policy = o }
|
33
|
+
opt.on('-d', '--directives DIRECTIVES_FILE', 'Havox directives file') { |o| args.havox_directives = o }
|
34
|
+
opt.on('-s', '--syntax trema,ovs,routeflow', [:trema, :ovs, :routeflow], 'Output syntax for generated rules (default: trema)') { |o| args.syntax = o }
|
35
|
+
opt.on('-f', '--[no-]force', 'Forces Havox to ignore field conflicts in rules generated by Merlin') { |o| args.force = o }
|
36
|
+
opt.on('-b', '--[no-]basic-policies', 'Automatically appends policies for basic protocols in the policies file') { |o| args.basic = o }
|
37
|
+
opt.on('-x', '--[no-]expand', 'Expands rules from VLAN-based to full predicates') { |o| args.expand = o }
|
38
|
+
opt.on('-o', '--[no-]output', 'Switches all occurrences of Enqueue action to Output action') { |o| args.output = o }
|
39
|
+
opt.on('--rules-only', 'Tells Havox to just output rules without loading anything') { |o| args.rules_only = o }
|
40
|
+
opt.on('--trema', 'Tells Havox to load Trema environment') { |o| args.trema = o }
|
41
|
+
end.parse!
|
42
|
+
|
43
|
+
# Sets all required environment variables to be read in the controller.
|
44
|
+
def set_environment_vars(args)
|
45
|
+
ENV['HAVOX_FORCE'] = args.force.to_s
|
46
|
+
ENV['HAVOX_BASIC'] = args.basic.to_s
|
47
|
+
ENV['HAVOX_EXPAND'] = args.expand.to_s
|
48
|
+
ENV['HAVOX_OUTPUT'] = args.output.to_s
|
49
|
+
ENV['HAVOX_SYNTAX'] = args.syntax.to_s
|
50
|
+
ENV['HAVOX_MERLIN_TOPOLOGY'] = args.merlin_topology
|
51
|
+
ENV['HAVOX_MERLIN_POLICY'] = args.merlin_policy
|
52
|
+
end
|
53
|
+
|
54
|
+
# Defines the Trema execution method.
|
55
|
+
def start_trema!(args)
|
56
|
+
puts 'Loading Havox with Trema...'
|
57
|
+
cmd = 'trema run lib/trema/controllers/main_controller.rb' \
|
58
|
+
" -c #{args.trema_topology}"
|
59
|
+
system(cmd)
|
60
|
+
rescue Interrupt
|
61
|
+
puts 'Closing.'
|
62
|
+
end
|
63
|
+
|
64
|
+
# Checks arguments for rules generation.
|
65
|
+
def files_ok?(args)
|
66
|
+
!(args.havox_directives.nil? && args.merlin_policy.nil?) &&
|
67
|
+
!args.merlin_topology.nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
# Checks arguments for Trema initialization.
|
71
|
+
def can_start_trema?(args)
|
72
|
+
!args.trema_topology.nil? && files_ok?(args)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Sets environment variables and starts Havox.
|
76
|
+
def set_env_and_start_trema!(args)
|
77
|
+
if can_start_trema?(args)
|
78
|
+
set_environment_vars(args)
|
79
|
+
start_trema!(args)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Transcompiles Havox directives to Merlin blocks and returns the resulting Merlin file.
|
84
|
+
def transcompile_to_merlin(args)
|
85
|
+
mln_filename = "./#{File.basename(args.havox_directives, '.hvx')}.mln"
|
86
|
+
eval File.read(args.havox_directives)
|
87
|
+
mln_blocks = Havox::Network.transcompile(args)
|
88
|
+
File.open(mln_filename, 'w') { |f| f.write(mln_blocks.join("\n")) }
|
89
|
+
mln_filename
|
90
|
+
end
|
91
|
+
|
92
|
+
# Calls the rules generation and outputs the rules.
|
93
|
+
def output_rules!(args)
|
94
|
+
if files_ok?(args)
|
95
|
+
args.merlin_policy = transcompile_to_merlin(args) unless args.havox_directives.nil?
|
96
|
+
puts Havox::Policy.new(args.to_h).to_json
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# After everything is defined, main execution flux starts here.
|
101
|
+
if args.rules_only
|
102
|
+
output_rules!(args)
|
103
|
+
elsif args.trema
|
104
|
+
set_env_and_start_trema!(args)
|
105
|
+
else
|
106
|
+
Havox::API.run!
|
107
|
+
end
|
data/havox.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'havox/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'havox'
|
7
|
+
spec.version = Havox::VERSION
|
8
|
+
spec.authors = ['Rodrigo Soares']
|
9
|
+
spec.email = ['silvars1@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = %q{A gem for making the generation of OpenFlow network rules easier.}
|
12
|
+
spec.description = %q{This gem offers a friendly way to deal with OpenFlow network policies generated by Merlin, integrating it with RouteFlow through a simple orchestration DSL.}
|
13
|
+
spec.homepage = 'https://github.com/rodrigosoares/havox'
|
14
|
+
spec.license = 'GPL-3.0'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = 'exe'
|
20
|
+
spec.executables = 'havox'
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
24
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
+
spec.add_development_dependency 'factory_girl', '~> 4.8'
|
27
|
+
spec.add_development_dependency 'awesome_print', '~> 1.7'
|
28
|
+
spec.add_runtime_dependency 'net-ssh', '~> 4.0'
|
29
|
+
spec.add_runtime_dependency 'net-scp', '~> 1.2'
|
30
|
+
spec.add_runtime_dependency 'trema', '~> 0.10.1'
|
31
|
+
spec.add_runtime_dependency 'colorize', '~> 0.8'
|
32
|
+
spec.add_runtime_dependency 'sinatra', '~> 2.0'
|
33
|
+
end
|
data/lib/havox.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'ipaddr'
|
3
|
+
require 'singleton'
|
4
|
+
require 'havox/version'
|
5
|
+
require 'havox/exceptions'
|
6
|
+
require 'havox/configuration'
|
7
|
+
require 'havox/modules/command'
|
8
|
+
require 'havox/modules/routeflow'
|
9
|
+
require 'havox/modules/merlin'
|
10
|
+
require 'havox/modules/field_parser'
|
11
|
+
require 'havox/modules/openflow10/ovs/actions'
|
12
|
+
require 'havox/modules/openflow10/ovs/matches'
|
13
|
+
require 'havox/modules/openflow10/routeflow/actions'
|
14
|
+
require 'havox/modules/openflow10/routeflow/matches'
|
15
|
+
require 'havox/modules/openflow10/trema/actions'
|
16
|
+
require 'havox/modules/openflow10/trema/matches'
|
17
|
+
require 'havox/classes/topology'
|
18
|
+
require 'havox/classes/node'
|
19
|
+
require 'havox/classes/edge'
|
20
|
+
require 'havox/classes/modified_policy'
|
21
|
+
require 'havox/classes/policy'
|
22
|
+
require 'havox/classes/rib'
|
23
|
+
require 'havox/classes/route'
|
24
|
+
require 'havox/classes/route_filler'
|
25
|
+
require 'havox/classes/rule'
|
26
|
+
require 'havox/classes/rule_sanitizer'
|
27
|
+
require 'havox/classes/rule_expander'
|
28
|
+
require 'havox/classes/translator'
|
29
|
+
require 'havox/dsl/directive.rb'
|
30
|
+
require 'havox/dsl/directive_proxy.rb'
|
31
|
+
require 'havox/dsl/network.rb'
|
32
|
+
require 'net/ssh'
|
33
|
+
require 'net/scp'
|
34
|
+
|
35
|
+
module Havox
|
36
|
+
class << self
|
37
|
+
attr_accessor :configuration
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.configuration
|
41
|
+
@configuration ||= Configuration.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.reset
|
45
|
+
@configuration = Configuration.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.configure
|
49
|
+
yield(configuration)
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'bundler/setup' # TODO: Remove this line after Havox is released to RubyGems.
|
2
|
+
require 'sinatra'
|
3
|
+
require 'colorize'
|
4
|
+
require 'havox'
|
5
|
+
require_relative '../../../config'
|
6
|
+
require_relative 'helpers/methods'
|
7
|
+
|
8
|
+
module Havox
|
9
|
+
class API < Sinatra::Base
|
10
|
+
set :bind, '0.0.0.0'
|
11
|
+
|
12
|
+
before { content_type :json }
|
13
|
+
|
14
|
+
# TODO: Make this read files from anywhere in the file system.
|
15
|
+
get '/rules/:name' do
|
16
|
+
base_dir = '/home/rod/Projetos/Mestrado/havox/lib/merlin'
|
17
|
+
opts = {
|
18
|
+
merlin_topology: "#{base_dir}/topologies/#{params[:name]}.dot",
|
19
|
+
merlin_policy: "#{base_dir}/policies/#{params[:name]}.mln",
|
20
|
+
force: params[:force].eql?('true'),
|
21
|
+
basic: params[:basic].eql?('true'),
|
22
|
+
expand: params[:expand].eql?('true'),
|
23
|
+
output: params[:output].eql?('true'),
|
24
|
+
syntax: params[:syntax]&.to_sym
|
25
|
+
}
|
26
|
+
Havox::Policy.new(opts).to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
post '/rules' do
|
30
|
+
dot_filepath = handle_file(params[:dot_file])
|
31
|
+
hvx_filepath = handle_file(params[:hvx_file])
|
32
|
+
pre_opts = {
|
33
|
+
qos: params[:qos],
|
34
|
+
preferred: params[:preferred],
|
35
|
+
arbitrary: params[:arbitrary]
|
36
|
+
}
|
37
|
+
mln_filepath = run_network(dot_filepath, hvx_filepath, pre_opts)
|
38
|
+
|
39
|
+
if mln_filepath.nil?
|
40
|
+
[].to_json
|
41
|
+
else
|
42
|
+
pos_opts = {
|
43
|
+
merlin_topology: dot_filepath,
|
44
|
+
merlin_policy: mln_filepath,
|
45
|
+
force: params[:force].eql?('true'),
|
46
|
+
basic: params[:basic].eql?('true'),
|
47
|
+
expand: params[:expand].eql?('true'),
|
48
|
+
output: params[:output].eql?('true'),
|
49
|
+
syntax: params[:syntax]&.to_sym
|
50
|
+
}
|
51
|
+
policy = Havox::Policy.new(pos_opts)
|
52
|
+
print_policy(policy, pos_opts)
|
53
|
+
policy.to_json
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|