trema 0.4.5 → 0.4.6
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 +4 -4
- data/Gemfile +4 -4
- data/Guardfile +8 -0
- data/Rakefile +2 -1
- data/bin/trema +4 -0
- data/cruise.rb +1 -1
- data/features/core/switch_manager.feature +2 -2
- data/features/examples/message.vendor-action.feature +2 -2
- data/features/examples/message.vendor-stats-request.feature +20 -0
- data/features/trema_commands/kill.feature +4 -0
- data/features/trema_commands/killall.feature +1 -0
- data/features/trema_commands/run.feature +20 -1
- data/ruby/trema/command/run.rb +4 -0
- data/ruby/trema/default_openflow_channel_port.rb +26 -0
- data/ruby/trema/dsl/configuration.rb +2 -1
- data/ruby/trema/open-vswitch.rb +2 -4
- data/ruby/trema/stats-reply.c +10 -1
- data/ruby/trema/stats-request.c +34 -1
- data/ruby/trema/vendor-stats-reply.rb +6 -2
- data/ruby/trema/version.rb +1 -1
- data/spec/trema/dsl/runner_spec.rb +1 -1
- data/spec/trema/dsl/syntax_spec.rb +1 -1
- data/spec/trema/shell/vswitch_spec.rb +1 -1
- data/spec/trema/stats-reply_spec.rb +2 -1
- data/spec/trema/stats-request_spec.rb +11 -0
- data/src/examples/cbench_switch/cbench-switch.rb +1 -0
- data/src/examples/cbench_switch/cbench_switch.c +1 -1
- data/src/examples/openflow_message/vendor-action.rb +4 -4
- data/src/examples/openflow_message/vendor-stats-request.rb +66 -0
- data/src/examples/simple_router/arp-table.rb +6 -17
- data/src/examples/simple_router/interface.rb +20 -29
- data/src/examples/simple_router/routing-table.rb +15 -22
- data/src/examples/simple_router/simple-router.rb +75 -64
- data/src/lib/chibach.c +3 -2
- data/src/lib/event_handler.c +55 -23
- data/src/lib/event_handler.h +0 -5
- data/src/lib/external_callback.c +126 -0
- data/src/lib/external_callback.h +46 -0
- data/src/lib/messenger.c +58 -35
- data/src/lib/openflow_message.c +32 -11
- data/src/lib/trema.c +13 -7
- data/src/lib/trema.h +1 -0
- data/src/lib/utility.c +13 -2
- data/src/switch_manager/secure_channel_receiver.c +6 -1
- data/src/switch_manager/switch.c +27 -26
- data/src/switch_manager/switch_manager.c +31 -10
- data/src/tremashark/packet_capture.c +3 -2
- data/src/tremashark/tremashark.c +2 -2
- data/trema.gemspec +1 -1
- data/unittests/lib/external_callback_test.c +282 -0
- data/unittests/lib/messenger_test.c +22 -0
- data/unittests/lib/openflow_message_test.c +1 -1
- data/unittests/lib/trema_test.c +1 -1
- data/unittests/switch_manager/switch_manager_test.c +3 -3
- metadata +12 -6
- data/src/examples/simple_router/router-utils.rb +0 -211
data/ruby/trema/version.rb
CHANGED
@@ -23,7 +23,7 @@ require "trema/packetin-filter"
|
|
23
23
|
|
24
24
|
describe Trema::DSL::Syntax do
|
25
25
|
before( :each ) do
|
26
|
-
@context = mock( "context", :port =>
|
26
|
+
@context = mock( "context", :port => 6653, :dump_to => nil )
|
27
27
|
@syntax = Trema::DSL::Syntax.new( @context )
|
28
28
|
end
|
29
29
|
|
@@ -41,7 +41,7 @@ describe Trema::Shell, ".vswitch" do
|
|
41
41
|
|
42
42
|
context "executed within a shell" do
|
43
43
|
before {
|
44
|
-
$config = mock( "config", :port =>
|
44
|
+
$config = mock( "config", :port => 6653 )
|
45
45
|
$context = mock( "context", :dump => true )
|
46
46
|
}
|
47
47
|
after { Trema::OpenflowSwitch[ "0xabc" ].shutdown! if Trema::OpenflowSwitch[ "0xabc" ] }
|
@@ -142,7 +142,7 @@ describe StatsReply, ".new( VALID OPTIONS )" do
|
|
142
142
|
its( :tx_packets ) { should == 10 }
|
143
143
|
its( :rx_bytes ) { should == 1454 }
|
144
144
|
its( :tx_bytes ) { should == 2314 }
|
145
|
-
its
|
145
|
+
its( :rx_dropped ) { should == 1 }
|
146
146
|
its( :tx_dropped ) { should == 1 }
|
147
147
|
its( :rx_errors ) { should == 1 }
|
148
148
|
its( :tx_errors ) { should == 1 }
|
@@ -178,6 +178,7 @@ describe StatsReply, ".new( VALID OPTIONS )" do
|
|
178
178
|
|
179
179
|
it { should respond_to( :to_s ) }
|
180
180
|
its( :vendor_id ) { should == 123 }
|
181
|
+
its( :data ) { should be_nil }
|
181
182
|
end
|
182
183
|
|
183
184
|
|
@@ -137,6 +137,7 @@ describe StatsRequest do
|
|
137
137
|
subject { VendorStatsRequest.new }
|
138
138
|
it_should_behave_like "any stats-request"
|
139
139
|
its( :vendor_id ) { should == 0x00004cff }
|
140
|
+
its( :data ) { should be_nil }
|
140
141
|
end
|
141
142
|
|
142
143
|
|
@@ -144,6 +145,16 @@ describe StatsRequest do
|
|
144
145
|
subject { VendorStatsRequest.new :vendor_id => 123 }
|
145
146
|
it_should_behave_like "any stats-request"
|
146
147
|
its( :vendor_id ) { should == 123 }
|
148
|
+
its( :data ) { should be_nil }
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
context "when .VendorStatsRequest.new(:data => value)" do
|
153
|
+
subject { VendorStatsRequest.new :data => data }
|
154
|
+
it_should_behave_like "any stats-request"
|
155
|
+
let( :data ) { "VENDOR DATA".unpack( "C*" ) }
|
156
|
+
its( :data ) { should == [86, 69, 78, 68, 79, 82, 32, 68, 65, 84, 65] }
|
157
|
+
its( :vendor_id ) { should == 0x00004cff }
|
147
158
|
end
|
148
159
|
end
|
149
160
|
|
@@ -22,6 +22,7 @@ class CbenchSwitch < Controller
|
|
22
22
|
def packet_in datapath_id, message
|
23
23
|
send_flow_mod_add(
|
24
24
|
datapath_id,
|
25
|
+
:cookie => 0,
|
25
26
|
:match => ExactMatch.from( message ),
|
26
27
|
:buffer_id => message.buffer_id,
|
27
28
|
:actions => ActionOutput.new( :port => message.in_port + 1 )
|
@@ -19,12 +19,12 @@
|
|
19
19
|
|
20
20
|
|
21
21
|
class VendorActionSampleController < Controller
|
22
|
-
|
23
|
-
|
22
|
+
OVS_VENDOR_ID = 0x00002320
|
23
|
+
OVSAST_NOTE = 8
|
24
24
|
|
25
25
|
def switch_ready datapath_id
|
26
|
-
body = [
|
27
|
-
actions = VendorAction.new(
|
26
|
+
body = [ OVSAST_NOTE, 0x54, 0x72, 0x65, 0x6d, 0x61, 0x00 ].pack( "nC6" )
|
27
|
+
actions = VendorAction.new( OVS_VENDOR_ID, body.unpack( "C*" ) )
|
28
28
|
send_flow_mod_modify(
|
29
29
|
datapath_id,
|
30
30
|
:hard_timeout => 60,
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#
|
2
|
+
# "Vendor Stats Request" sample application
|
3
|
+
#
|
4
|
+
# Copyright (C) 2013 NEC Corporation
|
5
|
+
#
|
6
|
+
# This program is free software; you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License, version 2, as
|
8
|
+
# published by the Free Software Foundation.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License along
|
16
|
+
# with this program; if not, write to the Free Software Foundation, Inc.,
|
17
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
|
+
#
|
19
|
+
|
20
|
+
|
21
|
+
class VendorStatsRequestSample < Controller
|
22
|
+
OVS_VENDOR_ID = 0x00002320
|
23
|
+
OVSST_FLOW = 0
|
24
|
+
|
25
|
+
def switch_ready datapath_id
|
26
|
+
send_vendor_stats_request datapath_id
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def stats_reply datapath_id, message
|
31
|
+
if message.type == StatsReply::OFPST_VENDOR
|
32
|
+
vendor_stats_reply datapath_id, message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
|
40
|
+
def vendor_stats_reply datapath_id, message
|
41
|
+
info "[vendor_stats_reply]"
|
42
|
+
info "vendor_id: 0x%08x" % message.stats.first.vendor_id
|
43
|
+
info "data: [#{ message.stats.first.data.map { | n | "0x%02x" % n }.join ", " }]"
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def send_vendor_stats_request datapath_id
|
48
|
+
data = [
|
49
|
+
OVSST_FLOW,
|
50
|
+
0x0, 0x0, 0x0, 0x0,
|
51
|
+
OFPP_NONE,
|
52
|
+
0x0,
|
53
|
+
0xff,
|
54
|
+
0x0, 0x0, 0x0
|
55
|
+
].pack( "NC4 nnCC3" )
|
56
|
+
vendor_request = VendorStatsRequest.new( :vendor_id => OVS_VENDOR_ID, :data => data.unpack( "C*" ) )
|
57
|
+
send_message( datapath_id, vendor_request )
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
### Local variables:
|
63
|
+
### mode: Ruby
|
64
|
+
### coding: utf-8-unix
|
65
|
+
### indent-tabs-mode: nil
|
66
|
+
### End:
|
@@ -17,16 +17,13 @@
|
|
17
17
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
18
|
#
|
19
19
|
|
20
|
-
|
21
20
|
class ARPEntry
|
22
21
|
include Trema::DefaultLogger
|
23
22
|
|
24
|
-
|
25
23
|
attr_reader :port
|
26
24
|
attr_reader :hwaddr
|
27
25
|
attr_writer :age_max
|
28
26
|
|
29
|
-
|
30
27
|
def initialize port, hwaddr, age_max
|
31
28
|
@port = port
|
32
29
|
@hwaddr = hwaddr
|
@@ -35,7 +32,6 @@ class ARPEntry
|
|
35
32
|
info "New entry: MAC addr = #{ @hwaddr.to_s }, port = #{ @port }"
|
36
33
|
end
|
37
34
|
|
38
|
-
|
39
35
|
def update port, hwaddr
|
40
36
|
@port = port
|
41
37
|
@hwaddr = hwaddr
|
@@ -43,7 +39,6 @@ class ARPEntry
|
|
43
39
|
info "Update entry: MAC addr = #{ @hwaddr.to_s }, port = #{ @port }"
|
44
40
|
end
|
45
41
|
|
46
|
-
|
47
42
|
def aged_out?
|
48
43
|
aged_out = Time.now - @last_updated > @age_max
|
49
44
|
info "Age out: An ARP entry (MAC address = #{ @hwaddr.to_s }, port number = #{ @port }) has been aged-out" if aged_out
|
@@ -51,40 +46,34 @@ class ARPEntry
|
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
54
|
-
|
55
49
|
class ARPTable
|
56
50
|
DEFAULT_AGE_MAX = 300
|
57
51
|
|
58
|
-
|
59
52
|
def initialize
|
60
53
|
@db = {}
|
61
54
|
end
|
62
55
|
|
63
|
-
|
64
56
|
def update port, ipaddr, hwaddr
|
65
|
-
entry = @db[
|
57
|
+
entry = @db[ipaddr.to_i]
|
66
58
|
if entry
|
67
|
-
entry.update(
|
59
|
+
entry.update(port, hwaddr)
|
68
60
|
else
|
69
|
-
new_entry = ARPEntry.new(
|
70
|
-
@db[
|
61
|
+
new_entry = ARPEntry.new(port, hwaddr, DEFAULT_AGE_MAX)
|
62
|
+
@db[ipaddr.to_i] = new_entry
|
71
63
|
end
|
72
64
|
end
|
73
65
|
|
74
|
-
|
75
66
|
def lookup ipaddr
|
76
|
-
@db[
|
67
|
+
@db[ipaddr.to_i]
|
77
68
|
end
|
78
69
|
|
79
|
-
|
80
70
|
def age
|
81
|
-
@db.delete_if do |
|
71
|
+
@db.delete_if do |ipaddr, entry|
|
82
72
|
entry.aged_out?
|
83
73
|
end
|
84
74
|
end
|
85
75
|
end
|
86
76
|
|
87
|
-
|
88
77
|
### Local variables:
|
89
78
|
### mode: Ruby
|
90
79
|
### coding: utf-8-unix
|
@@ -17,10 +17,10 @@
|
|
17
17
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
18
|
#
|
19
19
|
|
20
|
+
require 'arp-table'
|
21
|
+
require 'routing-table'
|
20
22
|
|
21
|
-
require
|
22
|
-
require "routing-table"
|
23
|
-
|
23
|
+
require 'pio'
|
24
24
|
|
25
25
|
class Interface
|
26
26
|
attr_reader :hwaddr
|
@@ -28,70 +28,61 @@ class Interface
|
|
28
28
|
attr_reader :masklen
|
29
29
|
attr_reader :port
|
30
30
|
|
31
|
-
|
32
31
|
def initialize options
|
33
|
-
@port = options[
|
34
|
-
@hwaddr = Mac.new(
|
35
|
-
@ipaddr =
|
36
|
-
@masklen = options[
|
32
|
+
@port = options[:port]
|
33
|
+
@hwaddr = Pio::Mac.new(options[:hwaddr])
|
34
|
+
@ipaddr = Pio::IPv4Address.new(options[:ipaddr])
|
35
|
+
@masklen = options[:masklen]
|
37
36
|
end
|
38
37
|
|
39
|
-
|
40
38
|
def has? mac
|
41
39
|
mac == hwaddr
|
42
40
|
end
|
43
41
|
end
|
44
42
|
|
45
|
-
|
46
43
|
class Interfaces
|
47
44
|
def initialize interfaces = []
|
48
45
|
@list = []
|
49
|
-
interfaces.each do |
|
50
|
-
@list << Interface.new(
|
46
|
+
interfaces.each do |each|
|
47
|
+
@list << Interface.new(each)
|
51
48
|
end
|
52
49
|
end
|
53
50
|
|
54
|
-
|
55
51
|
def find_by_port port
|
56
|
-
@list.find do |
|
52
|
+
@list.find do |each|
|
57
53
|
each.port == port
|
58
54
|
end
|
59
55
|
end
|
60
56
|
|
61
|
-
|
62
57
|
def find_by_ipaddr ipaddr
|
63
|
-
@list.find do |
|
64
|
-
each.ipaddr == ipaddr
|
58
|
+
@list.find do |each|
|
59
|
+
each.ipaddr.to_i == ipaddr.to_i
|
65
60
|
end
|
66
61
|
end
|
67
62
|
|
68
|
-
|
69
63
|
def find_by_prefix ipaddr
|
70
|
-
@list.find do |
|
64
|
+
@list.find do |each|
|
71
65
|
masklen = each.masklen
|
72
|
-
each.ipaddr.mask(
|
66
|
+
each.ipaddr.mask(masklen).to_s == ipaddr.mask(masklen).to_s
|
73
67
|
end
|
74
68
|
end
|
75
69
|
|
76
|
-
|
77
70
|
def find_by_port_and_ipaddr port, ipaddr
|
78
|
-
@list.find do |
|
79
|
-
each.port == port and each.ipaddr == ipaddr
|
71
|
+
@list.find do |each|
|
72
|
+
each.port == port and each.ipaddr.to_i == ipaddr.to_i
|
80
73
|
end
|
81
74
|
end
|
82
75
|
|
83
|
-
|
84
76
|
def ours? port, macda
|
85
|
-
|
77
|
+
true if macda.broadcast?
|
86
78
|
|
87
|
-
interface = find_by_port(
|
88
|
-
if not interface.nil? and interface.has?(
|
89
|
-
|
79
|
+
interface = find_by_port(port)
|
80
|
+
if not interface.nil? and interface.has?(macda)
|
81
|
+
true
|
90
82
|
end
|
91
83
|
end
|
92
84
|
end
|
93
85
|
|
94
|
-
|
95
86
|
### Local variables:
|
96
87
|
### mode: Ruby
|
97
88
|
### coding: utf-8
|
@@ -17,49 +17,42 @@
|
|
17
17
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
18
|
#
|
19
19
|
|
20
|
-
|
21
|
-
require "ipaddr"
|
22
|
-
|
20
|
+
require 'pio'
|
23
21
|
|
24
22
|
class RoutingTable
|
25
23
|
ADDR_LEN = 32
|
26
24
|
|
27
|
-
|
28
25
|
def initialize route = []
|
29
|
-
@db = Array.new(
|
30
|
-
route.each do |
|
31
|
-
add(
|
26
|
+
@db = Array.new(ADDR_LEN + 1) { Hash.new }
|
27
|
+
route.each do |each|
|
28
|
+
add(each)
|
32
29
|
end
|
33
30
|
end
|
34
31
|
|
35
|
-
|
36
32
|
def add options
|
37
|
-
dest =
|
38
|
-
masklen = options[
|
39
|
-
prefix = dest.mask(
|
40
|
-
@db[
|
33
|
+
dest = Pio::IPv4Address.new(options[:destination])
|
34
|
+
masklen = options[:masklen]
|
35
|
+
prefix = dest.mask(masklen)
|
36
|
+
@db[masklen][prefix.to_i] = Pio::IPv4Address.new(options[:nexthop])
|
41
37
|
end
|
42
38
|
|
43
|
-
|
44
39
|
def delete options
|
45
|
-
dest =
|
46
|
-
masklen = options[
|
47
|
-
prefix = dest.mask(
|
48
|
-
@db[
|
40
|
+
dest = Pio::IPv4Address.new(options[:destination])
|
41
|
+
masklen = options[:masklen]
|
42
|
+
prefix = dest.mask(masklen)
|
43
|
+
@db[masklen].delete(prefix.to_i)
|
49
44
|
end
|
50
45
|
|
51
|
-
|
52
46
|
def lookup dest
|
53
|
-
(
|
54
|
-
prefix = dest.mask(
|
55
|
-
entry = @db[
|
47
|
+
(0..ADDR_LEN).reverse_each do |masklen|
|
48
|
+
prefix = dest.mask(masklen)
|
49
|
+
entry = @db[masklen][prefix.to_i]
|
56
50
|
return entry if entry
|
57
51
|
end
|
58
52
|
nil
|
59
53
|
end
|
60
54
|
end
|
61
55
|
|
62
|
-
|
63
56
|
### Local variables:
|
64
57
|
### mode: Ruby
|
65
58
|
### coding: utf-8-unix
|
@@ -17,26 +17,21 @@
|
|
17
17
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require "routing-table"
|
24
|
-
|
20
|
+
require 'arp-table'
|
21
|
+
require 'interface'
|
22
|
+
require 'routing-table'
|
25
23
|
|
26
24
|
class SimpleRouter < Controller
|
27
|
-
include RouterUtils
|
28
|
-
|
29
25
|
|
30
26
|
def start
|
31
|
-
load
|
32
|
-
@interfaces = Interfaces.new(
|
27
|
+
load 'simple_router.conf'
|
28
|
+
@interfaces = Interfaces.new($interface)
|
33
29
|
@arp_table = ARPTable.new
|
34
|
-
@routing_table = RoutingTable.new(
|
30
|
+
@routing_table = RoutingTable.new($route)
|
35
31
|
end
|
36
32
|
|
37
|
-
|
38
|
-
|
39
|
-
return if not to_me?( message )
|
33
|
+
def packet_in(dpid, message)
|
34
|
+
return if not to_me?(message)
|
40
35
|
|
41
36
|
if message.arp_request?
|
42
37
|
handle_arp_request dpid, message
|
@@ -49,38 +44,33 @@ class SimpleRouter < Controller
|
|
49
44
|
end
|
50
45
|
end
|
51
46
|
|
52
|
-
|
53
47
|
private
|
54
48
|
|
55
|
-
|
56
|
-
def to_me?( message )
|
49
|
+
def to_me?(message)
|
57
50
|
return true if message.macda.broadcast?
|
58
51
|
|
59
|
-
interface = @interfaces.find_by_port(
|
60
|
-
if interface and interface.has?(
|
52
|
+
interface = @interfaces.find_by_port(message.in_port)
|
53
|
+
if interface and interface.has?(message.macda)
|
61
54
|
return true
|
62
55
|
end
|
63
56
|
end
|
64
57
|
|
65
|
-
|
66
|
-
def handle_arp_request( dpid, message )
|
58
|
+
def handle_arp_request(dpid, message)
|
67
59
|
port = message.in_port
|
68
60
|
daddr = message.arp_tpa
|
69
|
-
interface = @interfaces.find_by_port_and_ipaddr(
|
61
|
+
interface = @interfaces.find_by_port_and_ipaddr(port, daddr)
|
70
62
|
if interface
|
71
|
-
arp_reply = create_arp_reply_from(
|
72
|
-
packet_out dpid, arp_reply, SendOutPort.new(
|
63
|
+
arp_reply = create_arp_reply_from(message, interface.hwaddr)
|
64
|
+
packet_out dpid, arp_reply, SendOutPort.new(interface.port)
|
73
65
|
end
|
74
66
|
end
|
75
67
|
|
76
|
-
|
77
|
-
def handle_arp_reply( message )
|
68
|
+
def handle_arp_reply(message)
|
78
69
|
@arp_table.update message.in_port, message.arp_spa, message.arp_sha
|
79
70
|
end
|
80
71
|
|
81
|
-
|
82
|
-
|
83
|
-
if should_forward?( message )
|
72
|
+
def handle_ipv4(dpid, message)
|
73
|
+
if should_forward?(message)
|
84
74
|
forward dpid, message
|
85
75
|
elsif message.icmpv4_echo_request?
|
86
76
|
handle_icmpv4_echo_request dpid, message
|
@@ -89,38 +79,35 @@ class SimpleRouter < Controller
|
|
89
79
|
end
|
90
80
|
end
|
91
81
|
|
92
|
-
|
93
|
-
|
94
|
-
not @interfaces.find_by_ipaddr( message.ipv4_daddr )
|
82
|
+
def should_forward?(message)
|
83
|
+
not @interfaces.find_by_ipaddr(message.ipv4_daddr)
|
95
84
|
end
|
96
85
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
arp_entry = @arp_table.lookup( saddr )
|
86
|
+
def handle_icmpv4_echo_request(dpid, message)
|
87
|
+
interface = @interfaces.find_by_port(message.in_port)
|
88
|
+
saddr = message.ipv4_saddr
|
89
|
+
arp_entry = @arp_table.lookup(saddr)
|
102
90
|
if arp_entry
|
103
|
-
icmpv4_reply = create_icmpv4_reply(
|
104
|
-
packet_out dpid, icmpv4_reply, SendOutPort.new(
|
91
|
+
icmpv4_reply = create_icmpv4_reply(arp_entry, interface, message)
|
92
|
+
packet_out dpid, icmpv4_reply, SendOutPort.new(interface.port)
|
105
93
|
else
|
106
94
|
handle_unresolved_packet dpid, message, interface, saddr
|
107
95
|
end
|
108
96
|
end
|
109
97
|
|
98
|
+
def forward(dpid, message)
|
99
|
+
next_hop = resolve_next_hop(message.ipv4_daddr)
|
110
100
|
|
111
|
-
|
112
|
-
next_hop = resolve_next_hop( message.ipv4_daddr )
|
113
|
-
|
114
|
-
interface = @interfaces.find_by_prefix( next_hop )
|
101
|
+
interface = @interfaces.find_by_prefix(next_hop)
|
115
102
|
if not interface or interface.port == message.in_port
|
116
103
|
return
|
117
104
|
end
|
118
105
|
|
119
|
-
arp_entry = @arp_table.lookup(
|
106
|
+
arp_entry = @arp_table.lookup(next_hop)
|
120
107
|
if arp_entry
|
121
108
|
macsa = interface.hwaddr
|
122
109
|
macda = arp_entry.hwaddr
|
123
|
-
action = create_action_from(
|
110
|
+
action = create_action_from(macsa, macda, interface.port)
|
124
111
|
flow_mod dpid, message, action
|
125
112
|
packet_out dpid, message.data, action
|
126
113
|
else
|
@@ -128,27 +115,24 @@ class SimpleRouter < Controller
|
|
128
115
|
end
|
129
116
|
end
|
130
117
|
|
131
|
-
|
132
|
-
|
133
|
-
interface = @interfaces.find_by_prefix( daddr.value )
|
118
|
+
def resolve_next_hop(daddr)
|
119
|
+
interface = @interfaces.find_by_prefix(daddr.value)
|
134
120
|
if interface
|
135
|
-
daddr
|
121
|
+
daddr
|
136
122
|
else
|
137
|
-
@routing_table.lookup(
|
123
|
+
@routing_table.lookup(daddr.value)
|
138
124
|
end
|
139
125
|
end
|
140
126
|
|
141
|
-
|
142
|
-
def flow_mod( dpid, message, action )
|
127
|
+
def flow_mod(dpid, message, action)
|
143
128
|
send_flow_mod_add(
|
144
129
|
dpid,
|
145
|
-
:match => ExactMatch.from(
|
130
|
+
:match => ExactMatch.from(message),
|
146
131
|
:actions => action
|
147
132
|
)
|
148
133
|
end
|
149
134
|
|
150
|
-
|
151
|
-
def packet_out( dpid, packet, action )
|
135
|
+
def packet_out(dpid, packet, action)
|
152
136
|
send_packet_out(
|
153
137
|
dpid,
|
154
138
|
:data => packet,
|
@@ -156,22 +140,49 @@ class SimpleRouter < Controller
|
|
156
140
|
)
|
157
141
|
end
|
158
142
|
|
159
|
-
|
160
|
-
|
161
|
-
arp_request
|
162
|
-
packet_out dpid, arp_request, SendOutPort.new( interface.port )
|
143
|
+
def handle_unresolved_packet(dpid, message, interface, ipaddr)
|
144
|
+
arp_request = create_arp_request_from(interface, ipaddr)
|
145
|
+
packet_out dpid, arp_request, SendOutPort.new(interface.port)
|
163
146
|
end
|
164
147
|
|
165
|
-
|
166
|
-
def create_action_from( macsa, macda, port )
|
148
|
+
def create_action_from(macsa, macda, port)
|
167
149
|
[
|
168
|
-
SetEthSrcAddr.new(
|
169
|
-
SetEthDstAddr.new(
|
170
|
-
SendOutPort.new(
|
150
|
+
SetEthSrcAddr.new(macsa),
|
151
|
+
SetEthDstAddr.new(macda),
|
152
|
+
SendOutPort.new(port)
|
171
153
|
]
|
172
154
|
end
|
173
|
-
end
|
174
155
|
|
156
|
+
def create_arp_request_from(interface, addr)
|
157
|
+
Pio::Arp::Request.new(
|
158
|
+
:source_mac => interface.hwaddr,
|
159
|
+
:sender_protocol_address => interface.ipaddr,
|
160
|
+
:target_protocol_address => addr
|
161
|
+
).to_binary
|
162
|
+
end
|
163
|
+
|
164
|
+
def create_arp_reply_from(message, replyaddr)
|
165
|
+
Pio::Arp::Reply.new(
|
166
|
+
:source_mac => replyaddr,
|
167
|
+
:destination_mac => message.macsa,
|
168
|
+
:sender_protocol_address => message.arp_tpa,
|
169
|
+
:target_protocol_address => message.arp_spa
|
170
|
+
).to_binary
|
171
|
+
end
|
172
|
+
|
173
|
+
def create_icmpv4_reply(entry, interface, message)
|
174
|
+
request = Pio::Icmp.read(message.data)
|
175
|
+
Pio::Icmp::Reply.new(
|
176
|
+
:destination_mac => entry.hwaddr,
|
177
|
+
:source_mac => interface.hwaddr,
|
178
|
+
:ip_source_address => message.ipv4_daddr,
|
179
|
+
:ip_destination_address => message.ipv4_saddr,
|
180
|
+
:icmp_identifier => request.icmp_identifier,
|
181
|
+
:icmp_sequence_number => request.icmp_sequence_number,
|
182
|
+
:echo_data => request.echo_data
|
183
|
+
).to_binary
|
184
|
+
end
|
185
|
+
end
|
175
186
|
|
176
187
|
### Local variables:
|
177
188
|
### mode: Ruby
|