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
@@ -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
|
+
}
|