trema 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|