havox 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
@@ -0,0 +1,41 @@
|
|
1
|
+
module Havox
|
2
|
+
module OpenFlow10
|
3
|
+
module OVS
|
4
|
+
module Actions
|
5
|
+
extend Havox::FieldParser
|
6
|
+
|
7
|
+
def self.treat(actions_array, opts = {})
|
8
|
+
of_actions = []
|
9
|
+
actions_array.each do |obj|
|
10
|
+
of_actions <<
|
11
|
+
case obj[:action]
|
12
|
+
when 'Output' then basic_action(:output, obj[:arg_a])
|
13
|
+
when 'Enqueue' then output_or_enqueue(obj, opts[:output])
|
14
|
+
when 'SetField' then basic_action_from_set_field(obj)
|
15
|
+
else raise_unknown_action(obj)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
of_actions
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.basic_action_from_set_field(obj)
|
24
|
+
if obj[:arg_a].eql?('vlan')
|
25
|
+
obj[:arg_b].eql?('<none>') ? basic_action(:strip_vlan) : basic_action(:mod_vlan_vid, obj[:arg_b])
|
26
|
+
else
|
27
|
+
raise_unknown_action(obj)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.output_or_enqueue(obj, change_to_output)
|
32
|
+
if change_to_output
|
33
|
+
basic_action(:output, obj[:arg_a])
|
34
|
+
else
|
35
|
+
basic_action(:enqueue, obj[:arg_a], obj[:arg_b])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# This dictionary structure translates Merlin match fields to OpenVSwitch
|
2
|
+
# readable fields. More details can be found at:
|
3
|
+
# http://www.pica8.com/document/v2.3/pdf/ovs-commands-reference.pdf
|
4
|
+
|
5
|
+
module Havox
|
6
|
+
module OpenFlow10
|
7
|
+
module OVS
|
8
|
+
module Matches
|
9
|
+
extend Havox::FieldParser
|
10
|
+
|
11
|
+
FIELDS = {
|
12
|
+
'ethSrc' => :dl_src,
|
13
|
+
'ethDst' => :dl_dst,
|
14
|
+
'ethTyp' => :dl_type,
|
15
|
+
'ipSrc' => :nw_src,
|
16
|
+
'ipDst' => :nw_dst,
|
17
|
+
'ipProto' => :nw_proto,
|
18
|
+
'nwProto' => :nw_proto,
|
19
|
+
'port' => :in_port,
|
20
|
+
'switch' => :dp_id,
|
21
|
+
'tcpSrcPort' => :tp_src,
|
22
|
+
'tcpDstPort' => :tp_dst,
|
23
|
+
'vlanId' => :dl_vlan,
|
24
|
+
'vlanPcp' => :dl_vlan_pcp
|
25
|
+
}
|
26
|
+
|
27
|
+
def self.treat(hash)
|
28
|
+
hash[:nw_src] = parsed_ipv4(hash[:nw_src]) unless hash[:nw_src].nil?
|
29
|
+
hash[:nw_dst] = parsed_ipv4(hash[:nw_dst]) unless hash[:nw_dst].nil?
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Havox
|
2
|
+
module OpenFlow10
|
3
|
+
module RouteFlow
|
4
|
+
module Actions
|
5
|
+
extend Havox::FieldParser
|
6
|
+
|
7
|
+
def self.treat(actions_array, opts = {})
|
8
|
+
of_actions = []
|
9
|
+
actions_array.each do |obj|
|
10
|
+
of_actions <<
|
11
|
+
case obj[:action]
|
12
|
+
when 'Output' then basic_action(:output, obj[:arg_a].to_i)
|
13
|
+
when 'Enqueue' then output_or_enqueue(obj, opts[:output])
|
14
|
+
when 'SetField' then basic_action_from_set_field(obj)
|
15
|
+
else raise_unknown_action(obj)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
of_actions
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.basic_action_from_set_field(obj)
|
24
|
+
if obj[:arg_a].eql?('vlan')
|
25
|
+
if obj[:arg_b].eql?('<none>')
|
26
|
+
basic_action(:strip_vlan) # Inferred (vandervecken).
|
27
|
+
else
|
28
|
+
basic_action(:set_vlan_id, obj[:arg_b].to_i) # Inferred (vandervecken).
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise_unknown_action(obj)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.output_or_enqueue(obj, change_to_output)
|
36
|
+
if change_to_output
|
37
|
+
basic_action(:output, obj[:arg_a].to_i)
|
38
|
+
else
|
39
|
+
basic_action(:enqueue, obj[:arg_a].to_i, obj[:arg_b].to_i) # Inferred.
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# This dictionary structure translates Merlin match fields to RouteFlow
|
2
|
+
# readable fields. Since the current version of RouteFlow does not support
|
3
|
+
# all returned fields yet, some of them were inferred based on the others
|
4
|
+
# (those are marked as 'inferred'). As RouteFlow gets updated, the inferred
|
5
|
+
# names can be updated as well. RouteFlow's main repo can be accessed at:
|
6
|
+
# https://github.com/routeflow/RouteFlow.
|
7
|
+
|
8
|
+
module Havox
|
9
|
+
module OpenFlow10
|
10
|
+
module RouteFlow
|
11
|
+
module Matches
|
12
|
+
extend Havox::FieldParser
|
13
|
+
|
14
|
+
FIELDS = {
|
15
|
+
'ethSrc' => :ethernet_src, # Inferred.
|
16
|
+
'ethDst' => :ethernet,
|
17
|
+
'ethTyp' => :ethertype,
|
18
|
+
'ipSrc' => :ipv4_src, # Inferred.
|
19
|
+
'ipDst' => :ipv4,
|
20
|
+
'ipProto' => :nw_proto,
|
21
|
+
'nwProto' => :nw_proto,
|
22
|
+
'port' => :in_port, # Inferred.
|
23
|
+
'switch' => :dp_id,
|
24
|
+
'tcpSrcPort' => :tp_src,
|
25
|
+
'tcpDstPort' => :tp_dst,
|
26
|
+
'vlanId' => :vlan_id, # Inferred (vandervecken).
|
27
|
+
'vlanPcp' => :vlan_pcp # Inferred.
|
28
|
+
}
|
29
|
+
|
30
|
+
def self.treat(hash)
|
31
|
+
hash[:ethertype] = hash[:ethertype].to_i unless hash[:ethertype].nil?
|
32
|
+
hash[:ipv4_src] = parsed_ipv4(hash[:ipv4_src]) unless hash[:ipv4_src].nil?
|
33
|
+
hash[:ipv4] = parsed_ipv4(hash[:ipv4]) unless hash[:ipv4].nil?
|
34
|
+
hash[:nw_proto] = hash[:nw_proto].to_i unless hash[:nw_proto].nil?
|
35
|
+
hash[:in_port] = hash[:in_port].to_i unless hash[:in_port].nil?
|
36
|
+
hash[:tp_src] = hash[:tp_src].to_i unless hash[:tp_src].nil?
|
37
|
+
hash[:tp_dst] = hash[:tp_dst].to_i unless hash[:tp_dst].nil?
|
38
|
+
hash[:vlan_id] = hash[:vlan_id].to_i unless hash[:vlan_id].nil?
|
39
|
+
hash
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Havox
|
2
|
+
module OpenFlow10
|
3
|
+
module Trema
|
4
|
+
module Actions
|
5
|
+
extend Havox::FieldParser
|
6
|
+
|
7
|
+
def self.treat(actions_array, opts = {})
|
8
|
+
of_actions = []
|
9
|
+
actions_array.each do |obj|
|
10
|
+
of_actions <<
|
11
|
+
case obj[:action]
|
12
|
+
when 'Output' then basic_action(:output, obj[:arg_a].to_i)
|
13
|
+
when 'Enqueue' then output_or_enqueue(obj, opts[:output])
|
14
|
+
when 'SetField' then basic_action_from_set_field(obj)
|
15
|
+
else raise_unknown_action(obj)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
of_actions
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.basic_action_from_set_field(obj)
|
24
|
+
if obj[:arg_a].eql?('vlan')
|
25
|
+
if obj[:arg_b].eql?('<none>')
|
26
|
+
basic_action(:strip_vlan)
|
27
|
+
else
|
28
|
+
basic_action(:set_vlan_vid, obj[:arg_b].to_i)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise_unknown_action(obj)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.output_or_enqueue(obj, change_to_output)
|
36
|
+
if change_to_output
|
37
|
+
basic_action(:output, obj[:arg_a].to_i)
|
38
|
+
else
|
39
|
+
basic_action(:enqueue, obj[:arg_a].to_i, obj[:arg_b].to_i)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# This dictionary module translates Merlin match fields to Trema readable
|
2
|
+
# fields, based on the official OpenFlow 1.0 nomenclatures, as described in the
|
3
|
+
# OpenFlow specifications at:
|
4
|
+
# http://archive.openflow.org/documents/openflow-spec-v1.0.0.pdf
|
5
|
+
|
6
|
+
module Havox
|
7
|
+
module OpenFlow10
|
8
|
+
module Trema
|
9
|
+
module Matches
|
10
|
+
extend Havox::FieldParser
|
11
|
+
|
12
|
+
FIELDS = {
|
13
|
+
'ethSrc' => :source_mac_address,
|
14
|
+
'ethDst' => :destination_mac_address,
|
15
|
+
'ethTyp' => :ether_type, # https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
|
16
|
+
'ipSrc' => :source_ip_address,
|
17
|
+
'ipDst' => :destination_ip_address,
|
18
|
+
'ipProto' => :ip_protocol, # http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
19
|
+
'nwProto' => :ip_protocol,
|
20
|
+
'port' => :in_port,
|
21
|
+
'switch' => :dp_id,
|
22
|
+
'tcpSrcPort' => :transport_source_port,
|
23
|
+
'tcpDstPort' => :transport_destination_port,
|
24
|
+
'vlanId' => :vlan_vid,
|
25
|
+
'vlanPcp' => :vlan_priority
|
26
|
+
}
|
27
|
+
|
28
|
+
def self.treat(hash)
|
29
|
+
hash[:ether_type] = hash[:ether_type].to_i unless hash[:ether_type].nil?
|
30
|
+
hash[:source_ip_address] = parsed_ipv4(hash[:source_ip_address]) unless hash[:source_ip_address].nil?
|
31
|
+
hash[:destination_ip_address] = parsed_ipv4(hash[:destination_ip_address]) unless hash[:destination_ip_address].nil?
|
32
|
+
hash[:ip_protocol] = hash[:ip_protocol].to_i unless hash[:ip_protocol].nil?
|
33
|
+
hash[:in_port] = hash[:in_port].to_i unless hash[:in_port].nil?
|
34
|
+
hash[:transport_source_port] = hash[:transport_source_port].to_i unless hash[:transport_source_port].nil?
|
35
|
+
hash[:transport_destination_port] = hash[:transport_destination_port].to_i unless hash[:transport_destination_port].nil?
|
36
|
+
hash[:vlan_vid] = hash[:vlan_vid].to_i unless hash[:vlan_vid].nil?
|
37
|
+
hash[:vlan_priority] = hash[:vlan_priority].to_i unless hash[:vlan_priority].nil?
|
38
|
+
hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Havox
|
2
|
+
module RouteFlow
|
3
|
+
class << self
|
4
|
+
ENTRY_REGEX = /[A-Z>\*\s]{3}.*(via|is).*,.*$/
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def config
|
9
|
+
Havox.configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def cmd
|
13
|
+
Havox::Command
|
14
|
+
end
|
15
|
+
|
16
|
+
def ssh_connection
|
17
|
+
Net::SSH.start(config.rf_host, config.rf_user, password: config.rf_password) do |ssh|
|
18
|
+
yield(ssh)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(output)
|
23
|
+
result = output.each_line.map { |l| l.match(ENTRY_REGEX) }.compact
|
24
|
+
result.map(&:to_s)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run(command)
|
29
|
+
output = nil
|
30
|
+
ssh_connection { |ssh| output = ssh.exec!(command) }
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.fetch(vm_name, protocol = nil)
|
35
|
+
result = run(cmd.show_ip_route(vm_name, protocol))
|
36
|
+
result = parse(result)
|
37
|
+
result = Havox::RouteFiller.new(result).filled_routes
|
38
|
+
result
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.ribs(vm_names, opts = {})
|
42
|
+
routes = []
|
43
|
+
vm_names.each do |vm_name|
|
44
|
+
raw_routes = fetch(vm_name)
|
45
|
+
routes += raw_routes.map { |rr| Havox::Route.new(rr, vm_name, opts) }
|
46
|
+
end
|
47
|
+
routes
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
srcs := { h1; h2; h3; h4; h5; h6 };
|
2
|
+
exits_a := { h20 };
|
3
|
+
exits_b := { h60 };
|
4
|
+
|
5
|
+
foreach (s, d): cross(srcs, exits_a)
|
6
|
+
ipProto = 17 and ethTyp = 2048 and tcpDstPort = 80 -> .* s2 at min(100 Mbps);
|
7
|
+
|
8
|
+
foreach (s, d): cross(srcs, exits_b)
|
9
|
+
ipProto = 17 and ethTyp = 2048 and tcpDstPort = 25 -> .* s6 at min(100 Mbps);
|
@@ -0,0 +1,8 @@
|
|
1
|
+
foreach (s, d): cross({ h1; h3; h4 }, { h2 })
|
2
|
+
tcpDstPort = 80 -> .* s6 at min(100 Mbps);
|
3
|
+
|
4
|
+
foreach (s, d): cross({ h1; h3; h4 }, { h2 })
|
5
|
+
ipProto = udp -> .* s6 at min(100 Mbps);
|
6
|
+
|
7
|
+
foreach (s, d): cross({ h1; h3; h4 }, { h2 })
|
8
|
+
ipDst = 172.50.0.0 -> .* s6 at min(100 Mbps);
|
@@ -0,0 +1,8 @@
|
|
1
|
+
srcs := { h1; h2 };
|
2
|
+
dsts := { h4 };
|
3
|
+
|
4
|
+
foreach (s, d): cross(srcs, dsts)
|
5
|
+
ethTyp = 2048 and ipProto = 6 and tcpDstPort = 80 -> .* s2 s3 .* at min(100 Mbps);
|
6
|
+
|
7
|
+
foreach (s, d): cross(dsts, srcs)
|
8
|
+
ethTyp = 2048 and ipProto = 6 and tcpSrcPort = 80 -> .* s3 s2 .* at min(100 Mbps);
|
@@ -0,0 +1,15 @@
|
|
1
|
+
srcs := { h1; h2 };
|
2
|
+
dsts := { h4 };
|
3
|
+
all := { h1; h2; h3; h4 };
|
4
|
+
|
5
|
+
foreach (s, d): cross(srcs, dsts)
|
6
|
+
ethTyp = 2048 and ipProto = 6 and tcpDstPort = 80 -> .* s2 s3 .* at min(100 Mbps);
|
7
|
+
|
8
|
+
foreach (s, d): cross(dsts, srcs)
|
9
|
+
ethTyp = 2048 and ipProto = 6 and tcpSrcPort = 80 -> .* s3 s2 .* at min(100 Mbps);
|
10
|
+
|
11
|
+
foreach (s, d): cross(all, all)
|
12
|
+
ethTyp = 2048 and ipProto = 1 -> .* at min(100 Mbps);
|
13
|
+
|
14
|
+
foreach (s, d): cross(all, all)
|
15
|
+
ethTyp = 2054 -> .* at min(100 Mbps);
|
@@ -0,0 +1,7 @@
|
|
1
|
+
foreach (s, d): cross({ h1; h3; h4 }, { h1; h2; h3; h4 })
|
2
|
+
ethTyp = 2048 and ipProto = 6 and tcpDstPort = 80 -> .* s5 at min(100 Mbps);
|
3
|
+
|
4
|
+
(*
|
5
|
+
foreach (s, d): cross({ h1; h2; h3; h4 }, { h1; h2; h3; h4 })
|
6
|
+
ethTyp = 2048 and ipProto = 6 -> .* s8 at min(100 Mbps);
|
7
|
+
*)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
digraph g1 {
|
2
|
+
h1 [type = host, mac = "00:00:00:00:00:01", ip = "10.0.0.1"];
|
3
|
+
h2 [type = host, mac = "00:00:00:00:00:02", ip = "10.0.0.2"];
|
4
|
+
h3 [type = host, mac = "00:00:00:00:00:03", ip = "10.0.0.3"];
|
5
|
+
h4 [type = host, mac = "00:00:00:00:00:04", ip = "10.0.0.4"];
|
6
|
+
h5 [type = host, mac = "00:00:00:00:00:05", ip = "10.0.0.5"];
|
7
|
+
h6 [type = host, mac = "00:00:00:00:00:06", ip = "10.0.0.6"];
|
8
|
+
h20 [type = host, mac = "00:00:00:00:00:20", ip = "10.0.0.20"];
|
9
|
+
h60 [type = host, mac = "00:00:00:00:00:60", ip = "10.0.0.60"];
|
10
|
+
|
11
|
+
s1 [type = switch, ip = "11.0.0.1", id = 1];
|
12
|
+
s2 [type = switch, ip = "11.0.0.2", id = 2];
|
13
|
+
s3 [type = switch, ip = "11.0.0.3", id = 3];
|
14
|
+
s4 [type = switch, ip = "11.0.0.4", id = 4];
|
15
|
+
s5 [type = switch, ip = "11.0.0.5", id = 5];
|
16
|
+
s6 [type = switch, ip = "11.0.0.6", id = 6];
|
17
|
+
|
18
|
+
s1 -> h1 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
19
|
+
h1 -> s1 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
20
|
+
|
21
|
+
s2 -> h2 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
22
|
+
h2 -> s2 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
23
|
+
|
24
|
+
s3 -> h3 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
25
|
+
h3 -> s3 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
26
|
+
|
27
|
+
s4 -> h4 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
28
|
+
h4 -> s4 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
29
|
+
|
30
|
+
s5 -> h5 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
31
|
+
h5 -> s5 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
32
|
+
|
33
|
+
s6 -> h6 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
34
|
+
h6 -> s6 [src_port = 1, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
35
|
+
|
36
|
+
s2 -> h20 [src_port = 5, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
37
|
+
h20 -> s2 [src_port = 5, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
38
|
+
|
39
|
+
s6 -> h60 [src_port = 4, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
40
|
+
h60 -> s6 [src_port = 4, dst_port = 1, cost = 1, capacity = "1Gbps"];
|
41
|
+
|
42
|
+
s1 -> s2 [src_port = 2, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
43
|
+
s1 -> s3 [src_port = 3, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
44
|
+
|
45
|
+
s2 -> s1 [src_port = 2, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
46
|
+
s2 -> s3 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
47
|
+
s2 -> s4 [src_port = 4, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
48
|
+
|
49
|
+
s3 -> s1 [src_port = 2, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
50
|
+
s3 -> s2 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
51
|
+
s3 -> s4 [src_port = 4, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
52
|
+
s3 -> s5 [src_port = 5, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
53
|
+
|
54
|
+
s4 -> s2 [src_port = 2, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
55
|
+
s4 -> s3 [src_port = 3, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
56
|
+
s4 -> s6 [src_port = 4, dst_port = 2, cost = 1, capacity = "1Gbps"];
|
57
|
+
|
58
|
+
s5 -> s3 [src_port = 2, dst_port = 5, cost = 1, capacity = "1Gbps"];
|
59
|
+
s5 -> s6 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
60
|
+
|
61
|
+
s6 -> s4 [src_port = 2, dst_port = 4, cost = 1, capacity = "1Gbps"];
|
62
|
+
s6 -> s5 [src_port = 3, dst_port = 3, cost = 1, capacity = "1Gbps"];
|
63
|
+
}
|