pio 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +33 -2
  4. data/examples/echo_read.rb +1 -1
  5. data/examples/features_read.rb +1 -1
  6. data/examples/flow_mod_new.rb +13 -0
  7. data/examples/flow_mod_read.rb +6 -0
  8. data/features/echo_read.feature +27 -3
  9. data/features/features_read.feature +46 -2
  10. data/features/flow_mod_read.feature +186 -0
  11. data/features/hello_read.feature +9 -0
  12. data/features/packet_data/flow_mod_add.raw +0 -0
  13. data/features/packet_data/flow_mod_delete.raw +0 -0
  14. data/features/packet_data/flow_mod_delete_strict.raw +0 -0
  15. data/features/packet_data/flow_mod_modify.raw +0 -0
  16. data/features/packet_data/flow_mod_modify_strict.raw +0 -0
  17. data/features/packet_in_read.feature +13 -0
  18. data/features/packet_out_read.feature +16 -0
  19. data/features/step_definitions/packet_data_steps.rb +10 -1
  20. data/lib/pio.rb +1 -0
  21. data/lib/pio/echo.rb +10 -8
  22. data/lib/pio/enqueue.rb +1 -1
  23. data/lib/pio/features.rb +64 -7
  24. data/lib/pio/flow_mod.rb +86 -0
  25. data/lib/pio/hello.rb +4 -74
  26. data/lib/pio/ipv4_address.rb +1 -1
  27. data/lib/pio/match.rb +167 -0
  28. data/lib/pio/open_flow.rb +1 -0
  29. data/lib/pio/open_flow/actions.rb +65 -0
  30. data/lib/pio/open_flow/flags.rb +12 -9
  31. data/lib/pio/open_flow/message.rb +105 -21
  32. data/lib/pio/open_flow/phy_port.rb +31 -27
  33. data/lib/pio/open_flow/type.rb +1 -0
  34. data/lib/pio/packet_in.rb +2 -12
  35. data/lib/pio/packet_out.rb +4 -74
  36. data/lib/pio/send_out_port.rb +1 -0
  37. data/lib/pio/type/ip_address.rb +2 -7
  38. data/lib/pio/version.rb +1 -1
  39. data/pio.gemspec +8 -8
  40. data/spec/pio/echo/reply_spec.rb +61 -6
  41. data/spec/pio/echo/request_spec.rb +61 -6
  42. data/spec/pio/features/reply_spec.rb +81 -4
  43. data/spec/pio/features/request_spec.rb +88 -41
  44. data/spec/pio/flow_mod_spec.rb +151 -0
  45. data/spec/pio/hello_spec.rb +73 -56
  46. data/spec/pio/match_spec.rb +194 -0
  47. data/spec/pio/packet_in_spec.rb +35 -38
  48. data/spec/pio/packet_out_spec.rb +243 -182
  49. data/spec/pio/wildcards_spec.rb +115 -0
  50. metadata +37 -30
  51. data/features/packet_data/echo.raw +0 -0
  52. data/lib/pio/echo/message.rb +0 -49
  53. data/lib/pio/echo/reply.rb +0 -41
  54. data/lib/pio/echo/request.rb +0 -43
  55. data/lib/pio/features/reply.rb +0 -88
  56. data/lib/pio/features/request.rb +0 -68
  57. data/lib/pio/open_flow/parser.rb +0 -22
  58. data/spec/pio/echo_spec.rb +0 -49
  59. data/spec/pio/features_spec.rb +0 -96
@@ -0,0 +1,151 @@
1
+ require 'pio/flow_mod'
2
+
3
+ describe Pio::FlowMod do
4
+ Given(:dump) do
5
+ [
6
+ 0x01,
7
+ 0x0e,
8
+ 0x00, 0x50,
9
+ 0x00, 0x00, 0x00, 0x15,
10
+ 0x00, 0x38, 0x20, 0xfe, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
11
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
15
+ 0x00, 0x00,
16
+ 0x00, 0x00,
17
+ 0x00, 0x00,
18
+ 0xff, 0xff,
19
+ 0xff, 0xff, 0xff, 0xff,
20
+ 0x00, 0x02,
21
+ 0x00, 0x03,
22
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0xff, 0xff
23
+ ].pack('C*')
24
+ end
25
+
26
+ describe '.read' do
27
+ context 'with a flow_mod message' do
28
+ When(:flow_mod) do
29
+ Pio::FlowMod.read(dump)
30
+ end
31
+
32
+ Then { flow_mod.class == Pio::FlowMod }
33
+ Then { flow_mod.ofp_version == 0x1 }
34
+ Then { flow_mod.message_type == 0xe }
35
+ Then { flow_mod.message_length == 0x50 }
36
+ Then { flow_mod.transaction_id == 0x15 }
37
+ Then { flow_mod.xid == 0x15 }
38
+
39
+ Then { !flow_mod.body.empty? }
40
+ Then do
41
+ flow_mod.match.wildcards.keys == [
42
+ :dl_vlan,
43
+ :dl_src,
44
+ :dl_dst,
45
+ :dl_type,
46
+ :nw_proto,
47
+ :tp_src,
48
+ :tp_dst,
49
+ :nw_src_all,
50
+ :nw_dst_all,
51
+ :dl_vlan_pcp,
52
+ :nw_tos
53
+ ]
54
+ end
55
+ Then { flow_mod.match.in_port == 1 }
56
+ Then { flow_mod.match.dl_src == '00:00:00:00:00:00' }
57
+ Then { flow_mod.match.dl_dst == '00:00:00:00:00:00' }
58
+ Then { flow_mod.match.dl_vlan == 0 }
59
+ Then { flow_mod.match.dl_vlan_pcp == 0 }
60
+ Then { flow_mod.match.dl_type == 0 }
61
+ Then { flow_mod.match.nw_tos == 0 }
62
+ Then { flow_mod.match.nw_proto == 0 }
63
+ Then { flow_mod.match.nw_src == '0.0.0.0' }
64
+ Then { flow_mod.match.nw_dst == '0.0.0.0' }
65
+ Then { flow_mod.match.tp_src == 0 }
66
+ Then { flow_mod.match.tp_dst == 0 }
67
+ Then { flow_mod.cookie == 1 }
68
+ Then { flow_mod.command == :add }
69
+ Then { flow_mod.idle_timeout == 0 }
70
+ Then { flow_mod.hard_timeout == 0 }
71
+ Then { flow_mod.priority == 0xffff }
72
+ Then { flow_mod.buffer_id == 0xffffffff }
73
+ Then { flow_mod.out_port == 2 }
74
+ Then { flow_mod.flags == [:send_flow_rem, :check_overwrap] }
75
+ Then { flow_mod.actions.length == 1 }
76
+ Then { flow_mod.actions[0].is_a? Pio::SendOutPort }
77
+ Then { flow_mod.actions[0].port_number == 2 }
78
+ Then { flow_mod.actions[0].max_len == 2**16 - 1 }
79
+ end
80
+ end
81
+
82
+ describe '.new' do
83
+ context 'with a SendOutPort action' do
84
+ When(:flow_mod) do
85
+ Pio::FlowMod.new(transaction_id: 0x15,
86
+ buffer_id: 0xffffffff,
87
+ match: Pio::Match.new(in_port: 1),
88
+ cookie: 1,
89
+ command: :add,
90
+ priority: 0xffff,
91
+ out_port: 2,
92
+ flags: [:send_flow_rem, :check_overwrap],
93
+ actions: Pio::SendOutPort.new(2)
94
+ )
95
+ end
96
+
97
+ Then { flow_mod.class == Pio::FlowMod }
98
+ Then { flow_mod.ofp_version == 0x1 }
99
+ Then { flow_mod.message_type == 0xe }
100
+ Then { flow_mod.message_length == 0x50 }
101
+ Then { flow_mod.transaction_id == 0x15 }
102
+ Then { flow_mod.xid == 0x15 }
103
+
104
+ Then { !flow_mod.body.empty? }
105
+ Then do
106
+ flow_mod.match.wildcards.keys == [
107
+ :dl_vlan,
108
+ :dl_src,
109
+ :dl_dst,
110
+ :dl_type,
111
+ :nw_proto,
112
+ :tp_src,
113
+ :tp_dst,
114
+ :nw_src_all,
115
+ :nw_dst_all,
116
+ :dl_vlan_pcp,
117
+ :nw_tos
118
+ ]
119
+ end
120
+ Then { flow_mod.match.in_port == 1 }
121
+ Then { flow_mod.match.dl_src == '00:00:00:00:00:00' }
122
+ Then { flow_mod.match.dl_dst == '00:00:00:00:00:00' }
123
+ Then { flow_mod.match.dl_vlan == 0 }
124
+ Then { flow_mod.match.dl_vlan_pcp == 0 }
125
+ Then { flow_mod.match.dl_type == 0 }
126
+ Then { flow_mod.match.nw_tos == 0 }
127
+ Then { flow_mod.match.nw_proto == 0 }
128
+ Then { flow_mod.match.nw_src == '0.0.0.0' }
129
+ Then { flow_mod.match.nw_dst == '0.0.0.0' }
130
+ Then { flow_mod.match.tp_src == 0 }
131
+ Then { flow_mod.match.tp_dst == 0 }
132
+ Then { flow_mod.cookie == 1 }
133
+ Then { flow_mod.command == :add }
134
+ Then { flow_mod.idle_timeout == 0 }
135
+ Then { flow_mod.hard_timeout == 0 }
136
+ Then { flow_mod.priority == 0xffff }
137
+ Then { flow_mod.buffer_id == 0xffffffff }
138
+ Then { flow_mod.out_port == 2 }
139
+ Then { flow_mod.flags == [:send_flow_rem, :check_overwrap] }
140
+ Then { flow_mod.actions.length == 1 }
141
+ Then { flow_mod.actions[0].is_a? Pio::SendOutPort }
142
+ Then { flow_mod.actions[0].port_number == 2 }
143
+ Then { flow_mod.actions[0].max_len == 2**16 - 1 }
144
+
145
+ context '#to_binary' do
146
+ When(:binary) { flow_mod.to_binary }
147
+ Then { binary == dump }
148
+ end
149
+ end
150
+ end
151
+ end
@@ -2,82 +2,99 @@ require 'pio/hello'
2
2
 
3
3
  describe Pio::Hello do
4
4
  describe '.read' do
5
- context 'with a hello message' do
6
- Given(:hello_dump) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
7
-
8
- When(:hello) { Pio::Hello.read(hello_dump) }
5
+ When(:result) { Pio::Hello.read(binary) }
9
6
 
10
- Then { hello.class == Pio::Hello }
11
- Then { hello.ofp_version == 1 }
12
- Then { hello.message_type == 0 }
13
- Then { hello.message_length == 8 }
14
- Then { hello.transaction_id == 0 }
15
- Then { hello.xid == 0 }
16
- Then { hello.body.empty? }
7
+ context 'with a hello message' do
8
+ Given(:binary) { [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
9
+
10
+ Then { result.class == Pio::Hello }
11
+ Then { result.ofp_version == 1 }
12
+ Then { result.message_type == 0 }
13
+ Then { result.message_length == 8 }
14
+ Then { result.transaction_id == 0 }
15
+ Then { result.xid == 0 }
16
+ Then { result.body.empty? }
17
+ Then { result.body == '' }
17
18
  end
18
19
 
19
20
  context 'with a features-request message' do
20
- Given(:features_request_dump) { [1, 5, 0, 8, 0, 0, 0, 0].pack('C*') }
21
-
22
- When(:result) { Pio::Hello.read(features_request_dump) }
21
+ Given(:binary) { [1, 5, 0, 8, 0, 0, 0, 0].pack('C*') }
23
22
 
24
- Then { result == Failure(Pio::ParseError) }
23
+ Then { result == Failure(Pio::ParseError, 'Invalid Hello message.') }
25
24
  end
26
25
  end
27
26
 
28
27
  describe '.new' do
29
28
  context 'with no arguments' do
30
- When(:hello) { Pio::Hello.new }
31
-
32
- Then { hello.ofp_version == 1 }
33
- Then { hello.message_type == 0 }
34
- Then { hello.message_length == 8 }
35
- Then { hello.transaction_id == 0 }
36
- Then { hello.xid == 0 }
37
- Then { hello.body.empty? }
38
- Then { hello.to_binary == [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
29
+ When(:result) { Pio::Hello.new }
30
+
31
+ Then { result.ofp_version == 1 }
32
+ Then { result.message_type == 0 }
33
+ Then { result.message_length == 8 }
34
+ Then { result.transaction_id == 0 }
35
+ Then { result.xid == 0 }
36
+ Then { result.body.empty? }
37
+ Then { result.body == '' }
38
+ Then { result.to_binary == [1, 0, 0, 8, 0, 0, 0, 0].pack('C*') }
39
39
  end
40
40
 
41
41
  context 'with 123' do
42
- When(:hello) { Pio::Hello.new(123) }
43
-
44
- Then { hello.ofp_version == 1 }
45
- Then { hello.message_type == 0 }
46
- Then { hello.message_length == 8 }
47
- Then { hello.transaction_id == 123 }
48
- Then { hello.xid == 123 }
49
- Then { hello.body.empty? }
50
- Then { hello.to_binary == [1, 0, 0, 8, 0, 0, 0, 123].pack('C*') }
42
+ When(:result) { Pio::Hello.new(123) }
43
+
44
+ Then { result.ofp_version == 1 }
45
+ Then { result.message_type == 0 }
46
+ Then { result.message_length == 8 }
47
+ Then { result.transaction_id == 123 }
48
+ Then { result.xid == 123 }
49
+ Then { result.body.empty? }
50
+ Then { result.body == '' }
51
+ Then { result.to_binary == [1, 0, 0, 8, 0, 0, 0, 123].pack('C*') }
51
52
  end
52
53
 
53
- context 'with 2**32' do
54
- When(:result) { Pio::Hello.new(2**32) }
54
+ context 'with transaction_id: 123' do
55
+ When(:result) { Pio::Hello.new(transaction_id: 123) }
56
+
57
+ Then { result.ofp_version == 1 }
58
+ Then { result.message_type == 0 }
59
+ Then { result.message_length == 8 }
60
+ Then { result.transaction_id == 123 }
61
+ Then { result.xid == 123 }
62
+ Then { result.body.empty? }
63
+ Then { result.body == '' }
64
+ Then { result.to_binary == [1, 0, 0, 8, 0, 0, 0, 123].pack('C*') }
65
+ end
55
66
 
56
- Then { result == Failure(ArgumentError) }
67
+ context 'with xid: 123' do
68
+ When(:result) { Pio::Hello.new(xid: 123) }
69
+
70
+ Then { result.ofp_version == 1 }
71
+ Then { result.message_type == 0 }
72
+ Then { result.message_length == 8 }
73
+ Then { result.transaction_id == 123 }
74
+ Then { result.xid == 123 }
75
+ Then { result.body.empty? }
76
+ Then { result.body == '' }
77
+ Then { result.to_binary == [1, 0, 0, 8, 0, 0, 0, 123].pack('C*') }
57
78
  end
58
79
 
59
- context 'with transaction_id: 123' do
60
- When(:hello) { Pio::Hello.new(transaction_id: 123) }
61
-
62
- Then { hello.ofp_version == 1 }
63
- Then { hello.message_type == 0 }
64
- Then { hello.message_length == 8 }
65
- Then { hello.transaction_id == 123 }
66
- Then { hello.xid == 123 }
67
- Then { hello.body.empty? }
68
- Then { hello.to_binary == [1, 0, 0, 8, 0, 0, 0, 123].pack('C*') }
80
+ context 'with -1' do
81
+ When(:result) { Pio::Hello.new(-1) }
82
+
83
+ Then do
84
+ result ==
85
+ Failure(ArgumentError,
86
+ 'Transaction ID should be an unsigned 32-bit integer.')
87
+ end
69
88
  end
70
89
 
71
- context 'with xid: 123' do
72
- When(:hello) { Pio::Hello.new(xid: 123) }
73
-
74
- Then { hello.ofp_version == 1 }
75
- Then { hello.message_type == 0 }
76
- Then { hello.message_length == 8 }
77
- Then { hello.transaction_id == 123 }
78
- Then { hello.xid == 123 }
79
- Then { hello.body.empty? }
80
- Then { hello.to_binary == [1, 0, 0, 8, 0, 0, 0, 123].pack('C*') }
90
+ context 'with 2**32' do
91
+ When(:result) { Pio::Hello.new(2**32) }
92
+
93
+ Then do
94
+ result ==
95
+ Failure(ArgumentError,
96
+ 'Transaction ID should be an unsigned 32-bit integer.')
97
+ end
81
98
  end
82
99
 
83
100
  context 'with :INVALID_ARGUMENT' do
@@ -0,0 +1,194 @@
1
+ require 'pio/match'
2
+
3
+ describe Pio::Match do
4
+ describe '.read' do
5
+ When(:match) { Pio::Match.read(binary) }
6
+
7
+ context 'with a Match binary' do
8
+ Given(:binary) do
9
+ [
10
+ 0x00, 0x38, 0x20, 0xfe,
11
+ 0x00, 0x01,
12
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14
+ 0x00, 0x00,
15
+ 0x00,
16
+ 0x00,
17
+ 0x00, 0x00,
18
+ 0x00,
19
+ 0x00,
20
+ 0x00, 0x00,
21
+ 0x00, 0x00, 0x00, 0x00,
22
+ 0x00, 0x00, 0x00, 0x00,
23
+ 0x00, 0x00,
24
+ 0x00, 0x00
25
+ ].pack('C*')
26
+ end
27
+
28
+ Then do
29
+ match.wildcards.keys == [
30
+ :dl_vlan,
31
+ :dl_src,
32
+ :dl_dst,
33
+ :dl_type,
34
+ :nw_proto,
35
+ :tp_src,
36
+ :tp_dst,
37
+ :nw_src_all,
38
+ :nw_dst_all,
39
+ :dl_vlan_pcp,
40
+ :nw_tos
41
+ ]
42
+ end
43
+ Then { match.in_port == 1 }
44
+ Then { match.dl_src == '00:00:00:00:00:00' }
45
+ Then { match.dl_dst == '00:00:00:00:00:00' }
46
+ Then { match.dl_vlan == 0 }
47
+ Then { match.dl_vlan_pcp == 0 }
48
+ Then { match.dl_type == 0 }
49
+ Then { match.nw_tos == 0 }
50
+ Then { match.nw_proto == 0 }
51
+ Then { match.nw_src == '0.0.0.0' }
52
+ Then { match.nw_dst == '0.0.0.0' }
53
+ Then { match.tp_src == 0 }
54
+ Then { match.tp_dst == 0 }
55
+ end
56
+
57
+ context 'with a Match binary generated with Pio::Match.new' do
58
+ Given(:binary) { Pio::Match.new(nw_src: '192.168.1.0/24').to_binary_s }
59
+
60
+ Then do
61
+ match.wildcards.keys == [
62
+ :in_port,
63
+ :dl_vlan,
64
+ :dl_src,
65
+ :dl_dst,
66
+ :dl_type,
67
+ :nw_proto,
68
+ :tp_src,
69
+ :tp_dst,
70
+ :nw_src,
71
+ :nw_dst_all,
72
+ :dl_vlan_pcp,
73
+ :nw_tos
74
+ ]
75
+ end
76
+ And { match.wildcards[:nw_src] = 12 }
77
+ Then { match.in_port == 0 }
78
+ Then { match.dl_src == '00:00:00:00:00:00' }
79
+ Then { match.dl_dst == '00:00:00:00:00:00' }
80
+ Then { match.dl_vlan == 0 }
81
+ Then { match.dl_vlan_pcp == 0 }
82
+ Then { match.dl_type == 0 }
83
+ Then { match.nw_tos == 0 }
84
+ Then { match.nw_proto == 0 }
85
+ Then { match.nw_src == '192.168.1.0' }
86
+ Then { match.nw_src.prefixlen == 24 }
87
+ Then { match.nw_dst == '0.0.0.0' }
88
+ Then { match.tp_src == 0 }
89
+ Then { match.tp_dst == 0 }
90
+ end
91
+ end
92
+
93
+ describe '.new' do
94
+ context 'with in_port: 1' do
95
+ When(:match) { Pio::Match.new(in_port: 1) }
96
+
97
+ Then do
98
+ match.wildcards.keys == [
99
+ :dl_vlan,
100
+ :dl_src,
101
+ :dl_dst,
102
+ :dl_type,
103
+ :nw_proto,
104
+ :tp_src,
105
+ :tp_dst,
106
+ :nw_src_all,
107
+ :nw_dst_all,
108
+ :dl_vlan_pcp,
109
+ :nw_tos
110
+ ]
111
+ end
112
+ Then { match.in_port == 1 }
113
+ Then { match.dl_src == '00:00:00:00:00:00' }
114
+ Then { match.dl_dst == '00:00:00:00:00:00' }
115
+ Then { match.dl_vlan == 0 }
116
+ Then { match.dl_vlan_pcp == 0 }
117
+ Then { match.dl_type == 0 }
118
+ Then { match.nw_tos == 0 }
119
+ Then { match.nw_proto == 0 }
120
+ Then { match.nw_src == '0.0.0.0' }
121
+ Then { match.nw_dst == '0.0.0.0' }
122
+ Then { match.tp_src == 0 }
123
+ Then { match.tp_dst == 0 }
124
+ end
125
+
126
+ context "with nw_src: '192.168.1.0/24'" do
127
+ When(:match) { Pio::Match.new(nw_src: '192.168.1.0/24') }
128
+
129
+ Then do
130
+ match.wildcards.keys == [
131
+ :in_port,
132
+ :dl_vlan,
133
+ :dl_src,
134
+ :dl_dst,
135
+ :dl_type,
136
+ :nw_proto,
137
+ :tp_src,
138
+ :tp_dst,
139
+ :nw_src,
140
+ :nw_dst_all,
141
+ :dl_vlan_pcp,
142
+ :nw_tos
143
+ ]
144
+ end
145
+ Then { match.wildcards.fetch(:nw_src) == 8 }
146
+ Then { match.in_port == 0 }
147
+ Then { match.dl_src == '00:00:00:00:00:00' }
148
+ Then { match.dl_dst == '00:00:00:00:00:00' }
149
+ Then { match.dl_vlan == 0 }
150
+ Then { match.dl_vlan_pcp == 0 }
151
+ Then { match.dl_type == 0 }
152
+ Then { match.nw_tos == 0 }
153
+ Then { match.nw_proto == 0 }
154
+ Then { match.nw_src == '192.168.1.0/24' }
155
+ Then { match.nw_dst == '0.0.0.0' }
156
+ Then { match.tp_src == 0 }
157
+ Then { match.tp_dst == 0 }
158
+ end
159
+
160
+ context "with nw_dst: '192.168.1.0/24'" do
161
+ When(:match) { Pio::Match.new(nw_dst: '192.168.1.0/24') }
162
+
163
+ Then do
164
+ match.wildcards.keys == [
165
+ :in_port,
166
+ :dl_vlan,
167
+ :dl_src,
168
+ :dl_dst,
169
+ :dl_type,
170
+ :nw_proto,
171
+ :tp_src,
172
+ :tp_dst,
173
+ :nw_src_all,
174
+ :nw_dst,
175
+ :dl_vlan_pcp,
176
+ :nw_tos
177
+ ]
178
+ end
179
+ Then { match.wildcards.fetch(:nw_dst) == 8 }
180
+ Then { match.in_port == 0 }
181
+ Then { match.dl_src == '00:00:00:00:00:00' }
182
+ Then { match.dl_dst == '00:00:00:00:00:00' }
183
+ Then { match.dl_vlan == 0 }
184
+ Then { match.dl_vlan_pcp == 0 }
185
+ Then { match.dl_type == 0 }
186
+ Then { match.nw_tos == 0 }
187
+ Then { match.nw_proto == 0 }
188
+ Then { match.nw_src == '0.0.0.0' }
189
+ Then { match.nw_dst == '192.168.1.0/24' }
190
+ Then { match.tp_src == 0 }
191
+ Then { match.tp_dst == 0 }
192
+ end
193
+ end
194
+ end