wakame-vdc-dcmgr 11.06.0 → 11.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/Rakefile +19 -31
  2. data/bin/collector +6 -1
  3. data/config/db/migrations/0001_v1110_origin.rb +446 -0
  4. data/config/dcmgr.conf.example +51 -0
  5. data/lib/dcmgr.rb +99 -22
  6. data/lib/dcmgr/cli/base.rb +34 -1
  7. data/lib/dcmgr/cli/host.rb +24 -20
  8. data/lib/dcmgr/cli/image.rb +38 -19
  9. data/lib/dcmgr/cli/keypair.rb +16 -12
  10. data/lib/dcmgr/cli/network.rb +189 -81
  11. data/lib/dcmgr/cli/quota.rb +2 -2
  12. data/lib/dcmgr/cli/security_group.rb +106 -0
  13. data/lib/dcmgr/cli/spec.rb +144 -39
  14. data/lib/dcmgr/cli/storage.rb +16 -15
  15. data/lib/dcmgr/cli/tag.rb +20 -14
  16. data/lib/dcmgr/cli/vlan.rb +5 -5
  17. data/lib/dcmgr/drivers/backing_store.rb +32 -0
  18. data/lib/dcmgr/drivers/comstar.rb +81 -0
  19. data/lib/dcmgr/drivers/iijgio_storage.rb +9 -19
  20. data/lib/dcmgr/drivers/iscsi_target.rb +41 -0
  21. data/lib/dcmgr/drivers/kvm.rb +161 -28
  22. data/lib/dcmgr/drivers/linux_iscsi.rb +60 -0
  23. data/lib/dcmgr/drivers/local_storage.rb +24 -0
  24. data/lib/dcmgr/drivers/lxc.rb +167 -125
  25. data/lib/dcmgr/drivers/raw.rb +74 -0
  26. data/lib/dcmgr/drivers/s3_storage.rb +7 -19
  27. data/lib/dcmgr/drivers/snapshot_storage.rb +18 -28
  28. data/lib/dcmgr/drivers/storage_initiator.rb +28 -0
  29. data/lib/dcmgr/drivers/sun_iscsi.rb +32 -0
  30. data/lib/dcmgr/drivers/zfs.rb +77 -0
  31. data/lib/dcmgr/endpoints/core_api.rb +315 -263
  32. data/lib/dcmgr/endpoints/errors.rb +21 -10
  33. data/lib/dcmgr/endpoints/metadata.rb +360 -23
  34. data/lib/dcmgr/helpers/cli_helper.rb +6 -3
  35. data/lib/dcmgr/helpers/ec2_metadata_helper.rb +9 -0
  36. data/lib/dcmgr/helpers/nic_helper.rb +11 -0
  37. data/lib/dcmgr/helpers/snapshot_storage_helper.rb +34 -0
  38. data/lib/dcmgr/models/account.rb +0 -6
  39. data/lib/dcmgr/models/account_resource.rb +0 -4
  40. data/lib/dcmgr/models/base_new.rb +14 -2
  41. data/lib/dcmgr/models/dhcp_range.rb +38 -0
  42. data/lib/dcmgr/models/frontend_system.rb +0 -6
  43. data/lib/dcmgr/models/history.rb +0 -11
  44. data/lib/dcmgr/models/host_node.rb +131 -0
  45. data/lib/dcmgr/models/hostname_lease.rb +0 -8
  46. data/lib/dcmgr/models/image.rb +31 -18
  47. data/lib/dcmgr/models/instance.rb +137 -143
  48. data/lib/dcmgr/models/instance_nic.rb +52 -29
  49. data/lib/dcmgr/models/instance_security_group.rb +9 -0
  50. data/lib/dcmgr/models/instance_spec.rb +163 -31
  51. data/lib/dcmgr/models/ip_lease.rb +10 -21
  52. data/lib/dcmgr/models/mac_lease.rb +30 -11
  53. data/lib/dcmgr/models/network.rb +148 -27
  54. data/lib/dcmgr/models/physical_network.rb +18 -0
  55. data/lib/dcmgr/models/quota.rb +0 -10
  56. data/lib/dcmgr/models/request_log.rb +3 -18
  57. data/lib/dcmgr/models/security_group.rb +66 -0
  58. data/lib/dcmgr/models/security_group_rule.rb +145 -0
  59. data/lib/dcmgr/models/ssh_key_pair.rb +16 -19
  60. data/lib/dcmgr/models/{storage_pool.rb → storage_node.rb} +35 -25
  61. data/lib/dcmgr/models/tag.rb +0 -14
  62. data/lib/dcmgr/models/tag_mapping.rb +1 -7
  63. data/lib/dcmgr/models/vlan_lease.rb +2 -8
  64. data/lib/dcmgr/models/volume.rb +49 -37
  65. data/lib/dcmgr/models/volume_snapshot.rb +15 -17
  66. data/lib/dcmgr/node_modules/hva_collector.rb +69 -28
  67. data/lib/dcmgr/node_modules/instance_ha.rb +23 -12
  68. data/lib/dcmgr/node_modules/instance_monitor.rb +16 -2
  69. data/lib/dcmgr/node_modules/openflow_controller.rb +784 -0
  70. data/lib/dcmgr/node_modules/scheduler.rb +189 -0
  71. data/lib/dcmgr/node_modules/service_netfilter.rb +452 -227
  72. data/lib/dcmgr/node_modules/service_openflow.rb +731 -0
  73. data/lib/dcmgr/node_modules/sta_collector.rb +20 -0
  74. data/lib/dcmgr/node_modules/sta_tgt_initializer.rb +35 -0
  75. data/lib/dcmgr/rack/request_logger.rb +11 -6
  76. data/lib/dcmgr/rpc/hva_handler.rb +256 -110
  77. data/lib/dcmgr/rpc/sta_handler.rb +244 -0
  78. data/lib/dcmgr/scheduler.rb +122 -8
  79. data/lib/dcmgr/scheduler/host_node/exclude_same.rb +24 -0
  80. data/lib/dcmgr/scheduler/host_node/find_first.rb +12 -0
  81. data/lib/dcmgr/scheduler/host_node/least_usage.rb +28 -0
  82. data/lib/dcmgr/scheduler/host_node/per_instance.rb +18 -0
  83. data/lib/dcmgr/scheduler/host_node/specify_node.rb +26 -0
  84. data/lib/dcmgr/scheduler/network/flat_single.rb +23 -0
  85. data/lib/dcmgr/scheduler/network/nat_one_to_one.rb +23 -0
  86. data/lib/dcmgr/scheduler/network/per_instance.rb +39 -0
  87. data/lib/dcmgr/scheduler/network/vif_template.rb +19 -0
  88. data/lib/dcmgr/scheduler/storage_node/find_first.rb +13 -0
  89. data/lib/dcmgr/scheduler/storage_node/least_usage.rb +23 -0
  90. data/lib/dcmgr/storage_service.rb +39 -40
  91. data/lib/dcmgr/tags.rb +3 -3
  92. data/lib/dcmgr/version.rb +1 -1
  93. data/lib/dcmgr/vnet.rb +105 -0
  94. data/lib/dcmgr/vnet/factories.rb +141 -0
  95. data/lib/dcmgr/vnet/isolators/by_securitygroup.rb +21 -0
  96. data/lib/dcmgr/vnet/isolators/dummy.rb +17 -0
  97. data/lib/dcmgr/vnet/netfilter/cache.rb +51 -0
  98. data/lib/dcmgr/vnet/netfilter/chain.rb +66 -0
  99. data/lib/dcmgr/vnet/netfilter/controller.rb +193 -0
  100. data/lib/dcmgr/vnet/netfilter/ebtables_rule.rb +53 -0
  101. data/lib/dcmgr/vnet/netfilter/iptables_rule.rb +45 -0
  102. data/lib/dcmgr/vnet/netfilter/task_manager.rb +459 -0
  103. data/lib/dcmgr/vnet/tasks/accept_all_dns.rb +19 -0
  104. data/lib/dcmgr/vnet/tasks/accept_arp_broadcast.rb +24 -0
  105. data/lib/dcmgr/vnet/tasks/accept_arp_from_friends.rb +34 -0
  106. data/lib/dcmgr/vnet/tasks/accept_arp_from_gateway.rb +21 -0
  107. data/lib/dcmgr/vnet/tasks/accept_arp_to_host.rb +30 -0
  108. data/lib/dcmgr/vnet/tasks/accept_ip_from_friends.rb +26 -0
  109. data/lib/dcmgr/vnet/tasks/accept_ip_from_gateway.rb +23 -0
  110. data/lib/dcmgr/vnet/tasks/accept_ip_to_anywhere.rb +18 -0
  111. data/lib/dcmgr/vnet/tasks/accept_related_established.rb +45 -0
  112. data/lib/dcmgr/vnet/tasks/accept_wakame_dhcp_only.rb +33 -0
  113. data/lib/dcmgr/vnet/tasks/accept_wakame_dns_only.rb +33 -0
  114. data/lib/dcmgr/vnet/tasks/debug_iptables.rb +21 -0
  115. data/lib/dcmgr/vnet/tasks/drop_arp_forwarding.rb +27 -0
  116. data/lib/dcmgr/vnet/tasks/drop_arp_to_host.rb +24 -0
  117. data/lib/dcmgr/vnet/tasks/drop_ip_from_anywhere.rb +18 -0
  118. data/lib/dcmgr/vnet/tasks/drop_ip_spoofing.rb +34 -0
  119. data/lib/dcmgr/vnet/tasks/drop_mac_spoofing.rb +33 -0
  120. data/lib/dcmgr/vnet/tasks/exclude_from_nat.rb +47 -0
  121. data/lib/dcmgr/vnet/tasks/security_group.rb +37 -0
  122. data/lib/dcmgr/vnet/tasks/static_nat.rb +54 -0
  123. data/lib/dcmgr/vnet/tasks/translate_metadata_address.rb +32 -0
  124. data/web/metadata/config.ru +1 -1
  125. metadata +174 -89
  126. data/lib/dcmgr/cli/group.rb +0 -101
  127. data/lib/dcmgr/endpoints/core_api_mock.rb +0 -865
  128. data/lib/dcmgr/models/host_pool.rb +0 -122
  129. data/lib/dcmgr/models/instance_netfilter_group.rb +0 -16
  130. data/lib/dcmgr/models/netfilter_group.rb +0 -89
  131. data/lib/dcmgr/models/netfilter_rule.rb +0 -21
  132. data/lib/dcmgr/scheduler/find_last.rb +0 -16
  133. data/lib/dcmgr/scheduler/find_random.rb +0 -16
  134. data/lib/dcmgr/stm/instance.rb +0 -25
  135. data/lib/dcmgr/stm/snapshot_context.rb +0 -33
  136. data/lib/dcmgr/stm/volume_context.rb +0 -65
@@ -2,7 +2,6 @@
2
2
  module Dcmgr
3
3
  module NodeModules
4
4
  class InstanceMonitor < Isono::NodeModules::Base
5
- include Dcmgr::Rpc::KvmHelper
6
5
  include Dcmgr::Logger
7
6
 
8
7
  initialize_hook do
@@ -24,7 +23,14 @@ module Dcmgr
24
23
  instlst = rpc.request('hva-collector', 'get_alive_instances', manifest.node_id)
25
24
  instlst.find_all{|i| i[:state] == 'running' }.each { |i|
26
25
  begin
27
- check_kvm_process(i)
26
+ case i[:host_node][:hypervisor]
27
+ when 'kvm'
28
+ check_kvm_process(i)
29
+ when 'lxc'
30
+ check_lxc_process(i)
31
+ else
32
+ raise "Unknown hypervisor type: #{i[:host_node][:hypervisor]}"
33
+ end
28
34
  rescue Exception => e
29
35
  if i[:status] == 'online'
30
36
  logger.error("#{e.class}, #{e.message}")
@@ -57,6 +63,14 @@ module Dcmgr
57
63
  end
58
64
  end
59
65
 
66
+ private
67
+ def check_lxc_process(i)
68
+ container_status = `lxc-info -n #{i[:uuid]}`.chomp.split(" ")[2]
69
+ if container_status != "RUNNING"
70
+ raise "Unable to find the lxc container: #{i[:uuid]}"
71
+ end
72
+ end
73
+
60
74
  def rpc
61
75
  @rpc ||= Isono::NodeModules::RpcChannel.new(@node)
62
76
  end
@@ -0,0 +1,784 @@
1
+ # -*- coding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path('../../../../../trema/ruby', __FILE__)
3
+
4
+ require 'net/dhcp'
5
+ require 'eventmachine'
6
+ require 'trema'
7
+ require 'racket'
8
+
9
+ class IPAddr
10
+ def to_short
11
+ [(@addr >> 24) & 0xff, (@addr >> 16) & 0xff, (@addr >> 8) & 0xff, @addr & 0xff]
12
+ end
13
+ end
14
+
15
+ module Dcmgr
16
+ module NodeModules
17
+
18
+ class OpenFlowController < Trema::Controller
19
+ include Dcmgr::Logger
20
+
21
+ attr_reader :ports
22
+ attr_reader :ovs_ofctl
23
+ attr_reader :local_hw
24
+
25
+ @@route_directly = 3
26
+ @@load_dest_table = 4
27
+ @@send_src_table = 5
28
+
29
+ @@virtual_src = 6
30
+ @@virtual_dest = 7
31
+
32
+ # Re-number these...
33
+ @@arp_antispoof_table = 10
34
+ @@arp_route_table = 11
35
+ @@metadata_outgoing_table = 12
36
+ @@metadata_incoming_table = 13
37
+
38
+ @@mac_route_table = 14
39
+
40
+ def initialize service_openflow
41
+ @ports = {}
42
+ @service_openflow = service_openflow
43
+ @ovs_ofctl = OvsOfctl.new service_openflow.node.manifest.config
44
+ end
45
+
46
+ def start
47
+ logger.info "starting OpenFlow controller."
48
+ end
49
+
50
+ def switch_ready datapath_id
51
+ logger.info "switch_ready from %#x." % datapath_id
52
+ ports.clear
53
+
54
+ # There's a short period of time between the switch being
55
+ # activated and features_reply installing flow.
56
+ send_message datapath_id, Trema::FeaturesRequest.new
57
+ end
58
+
59
+ def features_reply message
60
+ logger.info "features_reply from %#x." % message.datapath_id
61
+ logger.debug "datapath_id: %#x" % message.datapath_id
62
+ logger.debug "transaction_id: %#x" % message.transaction_id
63
+ logger.debug "n_buffers: %u" % message.n_buffers
64
+ logger.debug "n_tables: %u" % message.n_tables
65
+ logger.debug "capabilities: %u" % message.capabilities
66
+ logger.debug "actions: %u" % message.actions
67
+ logger.info "ports: %s" % message.ports.collect { | each | each.number }.sort.join( ", " )
68
+
69
+ message.ports.each do | each |
70
+ if each.number == OFPP_LOCAL
71
+ @local_hw = each.hw_addr
72
+ logger.debug "OFPP_LOCAL: hw_addr:#{@local_hw.to_s}"
73
+ end
74
+ end
75
+
76
+ message.ports.each do | each |
77
+ port = OpenFlowPort.new(each)
78
+ port.is_active = true
79
+ ports[each.number] = port
80
+
81
+ if each.number >= OFPP_MAX
82
+ # Do nothing...
83
+ elsif each.name =~ /^eth/
84
+ @service_openflow.add_eth port
85
+ elsif each.name =~ /^vif-/
86
+ @service_openflow.add_instance port
87
+ elsif each.name =~ /^gre-/
88
+ @service_openflow.add_tunnel port
89
+ else
90
+ end
91
+ end
92
+
93
+ # Build the routing flow table and some other flows using
94
+ # ovs-ofctl due to the lack of multiple tables support, which
95
+ # was introduced in of-spec 1.1.
96
+
97
+ #
98
+ # Classification
99
+ #
100
+ flows = []
101
+
102
+ # DHCP queries from instances and network should always go to
103
+ # local host, while queries from local host should go to the
104
+ # network.
105
+ flows << ["priority=#{5},udp,dl_dst=ff:ff:ff:ff:ff:ff,nw_src=0.0.0.0,nw_dst=255.255.255.255,tp_src=68,tp_dst=67", "local"]
106
+
107
+ flows << ["priority=#{3},arp", "resubmit(,#{@@arp_antispoof_table})"]
108
+ flows << ["priority=#{3},icmp", "resubmit(,#{@@load_dest_table})"]
109
+ flows << ["priority=#{3},tcp", "resubmit(,#{@@load_dest_table})"]
110
+ flows << ["priority=#{3},udp", "resubmit(,#{@@load_dest_table})"]
111
+
112
+ flows << ["priority=#{2},in_port=local", "resubmit(,#{@@route_directly})"]
113
+
114
+ #
115
+ # MAC address routing
116
+ #
117
+
118
+ flows << ["priority=#{1},table=#{@@mac_route_table},dl_dst=#{@local_hw.to_s}", "local"]
119
+ flows << ["priority=#{1},table=#{@@route_directly},dl_dst=#{@local_hw.to_s}", "local"]
120
+ flows << ["priority=#{1},table=#{@@load_dest_table},dl_dst=#{@local_hw.to_s}", "load:#{OFPP_LOCAL}->NXM_NX_REG0[],resubmit(,#{@@send_src_table})"]
121
+
122
+ # Some flows depend on only local being able to send packets
123
+ # with the local mac and ip address, so drop those.
124
+ flows << ["priority=#{6},table=#{@@send_src_table},in_port=local", "output:NXM_NX_REG0[]"]
125
+ flows << ["priority=#{5},table=#{@@send_src_table},dl_src=#{@local_hw.to_s}", "drop"]
126
+ flows << ["priority=#{5},table=#{@@send_src_table},ip,nw_src=#{Isono::Util.default_gw_ipaddr}", "drop"]
127
+
128
+ #
129
+ # ARP routing table
130
+ #
131
+
132
+ # ARP anti-spoofing flows.
133
+ flows << ["priority=#{1},table=#{@@arp_antispoof_table},arp,in_port=local", "resubmit(,#{@@arp_route_table})"]
134
+
135
+ # Replace drop actions with table default action.
136
+ flows << ["priority=#{0},table=#{@@arp_antispoof_table},arp", "drop"]
137
+
138
+ # TODO: How will this handle packets from host or eth0 that
139
+ # spoof the mac of an instance?
140
+ flows << ["priority=#{1},table=#{@@arp_route_table},arp,dl_dst=#{@local_hw.to_s}", "local"]
141
+
142
+ #
143
+ # Meta-data connections
144
+ #
145
+ flows << ["priority=#{5},tcp,nw_dst=169.254.169.254,tp_dst=80", "resubmit(,#{@@metadata_outgoing_table})"]
146
+ flows << ["priority=#{5},tcp,nw_src=#{Isono::Util.default_gw_ipaddr},tp_src=#{9002}", "resubmit(,#{@@metadata_incoming_table})"]
147
+
148
+ flows << ["priority=#{4},table=#{@@metadata_outgoing_table},in_port=local", "drop"]
149
+ flows << ["priority=#{0},table=#{@@metadata_outgoing_table}", "controller"]
150
+
151
+ @ovs_ofctl.add_flows_from_list flows
152
+ @service_openflow.networks.each { |network| update_network network[1] }
153
+ end
154
+
155
+ def delete_port port
156
+ port.lock.synchronize {
157
+ return unless port.is_active
158
+ port.is_active = false
159
+
160
+ @ovs_ofctl.del_flows_from_list port.active_flows
161
+ port.active_flows.clear
162
+ port.queued_flows.clear
163
+ ports.delete port.port_info.number
164
+ }
165
+ end
166
+
167
+ def port_status message
168
+ logger.info "port_status from %#x." % message.datapath_id
169
+ logger.debug "datapath_id: %#x" % message.datapath_id
170
+ logger.debug "reason: #{message.reason}"
171
+ logger.debug "in_port: #{message.phy_port.number}"
172
+ logger.debug "hw_addr: #{message.phy_port.hw_addr}"
173
+ logger.debug "state: %#x" % message.phy_port.state
174
+
175
+ case message.reason
176
+ when OFPPR_ADD
177
+ logger.info "Adding port: port:#{message.phy_port.number} name:#{message.phy_port.name}."
178
+ raise "OpenFlowPort" if ports.has_key? message.phy_port.number
179
+
180
+ delete_port ports[message.phy_port.number] if ports.has_key? message.phy_port.number
181
+
182
+ port = OpenFlowPort.new(message.phy_port)
183
+ port.is_active = true
184
+ ports[message.phy_port.number] = port
185
+
186
+ @service_openflow.add_eth port if message.phy_port.name =~ /^eth/
187
+ @service_openflow.add_instance port if message.phy_port.name =~ /^vif-/
188
+ @service_openflow.add_tunnel port if message.phy_port.name =~ /^gre-/
189
+
190
+ when OFPPR_DELETE
191
+ logger.info "Deleting instance port: port:#{message.phy_port.number}."
192
+ raise "UnknownOpenflowPort" if not ports.has_key? message.phy_port.number
193
+
194
+ delete_port ports[message.phy_port.number] if ports.has_key? message.phy_port.number
195
+
196
+ when OFPPR_MODIFY
197
+ logger.info "Ignoring port modify..."
198
+ end
199
+ end
200
+
201
+ def packet_in datapath_id, message
202
+ port = ports[message.in_port]
203
+
204
+ if port.nil?
205
+ logger.debug "Dropping processing of packet, unknown port."
206
+ return
207
+ end
208
+
209
+ if message.arp?
210
+ logger.debug "Got ARP packet; port:#{message.in_port} source:#{message.arp_sha.to_s}:#{message.arp_spa.to_s} dest:#{message.arp_tha.to_s}:#{message.arp_tpa.to_s}."
211
+ return if port.network.nil?
212
+
213
+ if message.arp_oper == Racket::L3::ARP::ARPOP_REQUEST and message.arp_tpa.to_i == port.network.dhcp_ip.to_i
214
+ send_arp(datapath_id, message.in_port, Racket::L3::ARP::ARPOP_REPLY,
215
+ port.network.dhcp_hw.to_s, port.network.dhcp_ip.to_s,
216
+ message.macsa.to_s, message.arp_spa.to_s)
217
+ end
218
+
219
+ return
220
+ end
221
+
222
+ if message.ipv4? and message.tcp?
223
+ logger.debug "Got IPv4/TCP packet; port:#{message.in_port} source:#{message.ipv4_saddr.to_s}:#{message.tcp_src_port} dest:#{message.ipv4_daddr.to_s}:#{message.tcp_dst_port}."
224
+
225
+ # Add dynamic NAT flows for meta-data connections.
226
+ if message.ipv4_daddr.to_s == "169.254.169.254" and message.tcp_dst_port == 80
227
+ install_dnat_entry datapath_id, message, @@metadata_outgoing_table, @@metadata_incoming_table, OFPP_LOCAL, @local_hw, Isono::Util.default_gw_ipaddr, 9002
228
+ send_packet_out(datapath_id, :packet_in => message, :actions => Trema::ActionOutput.new( :port => OFPP_TABLE ) )
229
+ return
230
+ end
231
+
232
+ end
233
+
234
+ if message.ipv4? and message.udp?
235
+ logger.debug "Got IPv4/UDP packet; port:#{message.in_port} source:#{message.ipv4_saddr.to_s}:#{message.udp_src_port} dest:#{message.ipv4_daddr.to_s}:#{message.udp_dst_port}."
236
+
237
+ return if port.network.nil?
238
+
239
+ if message.udp_src_port == 68 and message.udp_dst_port == 67
240
+ dhcp_in = DHCP::Message.from_udp_payload(message.udp_payload)
241
+
242
+ logger.debug "DHCP: message:#{dhcp_in.to_s}."
243
+
244
+ if port.network.dhcp_ip.nil?
245
+ logger.debug "DHCP: Port has no dhcp_ip: port:#{port.inspect}"
246
+ return
247
+ end
248
+
249
+ # Check incoming type...
250
+ message_type = dhcp_in.options.select { |each| each.type == $DHCP_MESSAGETYPE }
251
+ return if message_type.empty? or message_type[0].payload.empty?
252
+
253
+ # Verify dhcp_in values...
254
+
255
+ if message_type[0].payload[0] == $DHCP_MSG_DISCOVER
256
+ logger.debug "DHCP send: DHCP_MSG_OFFER."
257
+ dhcp_out = DHCP::Offer.new(:options => [DHCP::MessageTypeOption.new(:payload => [$DHCP_MSG_OFFER])])
258
+ elsif message_type[0].payload[0] == $DHCP_MSG_REQUEST
259
+ logger.debug "DHCP send: DHCP_MSG_ACK."
260
+ dhcp_out = DHCP::ACK.new(:options => [DHCP::MessageTypeOption.new(:payload => [$DHCP_MSG_ACK])])
261
+ else
262
+ logger.debug "DHCP send: no handler."
263
+ return
264
+ end
265
+
266
+ dhcp_out.xid = dhcp_in.xid
267
+ dhcp_out.yiaddr = Trema::IP.new(port.ip).to_i
268
+ # Verify instead that discover has the right mac address.
269
+ dhcp_out.chaddr = Trema::Mac.new(port.mac).to_short
270
+ dhcp_out.siaddr = port.network.dhcp_ip.to_i
271
+
272
+ subnet_mask = IPAddr.new(IPAddr::IN4MASK, Socket::AF_INET).mask(port.network.prefix)
273
+
274
+ dhcp_out.options << DHCP::ServerIdentifierOption.new(:payload => port.network.dhcp_ip.to_short)
275
+ dhcp_out.options << DHCP::IPAddressLeaseTimeOption.new(:payload => [ 0xff, 0xff, 0xff, 0xff ])
276
+ dhcp_out.options << DHCP::BroadcastAddressOption.new(:payload => (port.network.ipv4_network | ~subnet_mask).to_short)
277
+ # Host name 'abcdefgh'.
278
+ # Domain name 'foo.local'
279
+ # Domain name server
280
+ # dhcp_out.options << DHCP::RouterOption.new(:payload => port.network.dhcp_ip.split('.').collect { | each | each.to_i })
281
+ dhcp_out.options << DHCP::SubnetMaskOption.new(:payload => subnet_mask.to_short)
282
+
283
+ logger.debug "DHCP send: output:#{dhcp_out.to_s}."
284
+ send_udp(datapath_id, message.in_port, port.network.dhcp_hw.to_s, port.network.dhcp_ip.to_s, 67, port.mac.to_s, port.ip, 68, dhcp_out.pack)
285
+ end
286
+ end
287
+ end
288
+
289
+ def vendor message
290
+ logger.debug "vendor message from #{message.datapath_id.to_hex}."
291
+ logger.debug "transaction_id: #{message.transaction_id.to_hex}"
292
+ logger.debug "data: #{message.buffer.unpack('H*')}"
293
+ end
294
+
295
+ #
296
+ # Public functions
297
+ #
298
+
299
+ def install_dnat_entry datapath_id, message, outgoing_table, incoming_table, dest_port, dest_hw, dest_ip, dest_tp
300
+ logger.info "Installing DNAT entry: #{dest_port} #{dest_hw} #{dest_ip}:#{dest_tp}"
301
+
302
+ msg_nw_src = message.ipv4_saddr.to_s
303
+ msg_nw_dst = message.ipv4_daddr.to_s
304
+
305
+ # We don't need to match against the IP or port used by the
306
+ # classifier to pass the flow to these tables.
307
+
308
+ prefix = "priority=3,idle_timeout=#{300},tcp"
309
+
310
+ prefix_outgoing = "#{prefix},table=#{outgoing_table},#{@ovs_ofctl.arg_in_port message.in_port}"
311
+ # classifier_outgoing = "nw_dst=#{msg_nw_dst},tp_dst=#{message.tcp_dst_port}"
312
+ match_outgoing = "dl_src=#{message.macsa.to_s},dl_dst=#{message.macda.to_s},nw_src=#{msg_nw_src},tp_src=#{message.tcp_src_port}"
313
+ action_outgoing = "mod_dl_dst:#{dest_hw},mod_nw_dst:#{dest_ip},mod_tp_dst:#{dest_tp},#{@ovs_ofctl.arg_output dest_port}"
314
+
315
+ prefix_incoming = "#{prefix},table=#{incoming_table},#{@ovs_ofctl.arg_in_port dest_port}"
316
+ # classifier_incoming = "nw_src=#{dest_ip},tp_src=#{dest_tp}"
317
+ match_incoming = "dl_src=#{dest_hw.to_s},dl_dst=#{message.macsa.to_s},nw_dst=#{msg_nw_src},tp_dst=#{message.tcp_src_port}"
318
+ action_incoming = "mod_dl_src:#{message.macda.to_s},mod_nw_src:#{msg_nw_dst},mod_tp_src:#{message.tcp_dst_port},#{@ovs_ofctl.arg_output message.in_port}"
319
+
320
+ @ovs_ofctl.add_flow "#{prefix_outgoing},#{match_outgoing}", action_outgoing
321
+ @ovs_ofctl.add_flow "#{prefix_incoming},#{match_incoming}", action_incoming
322
+ end
323
+
324
+ def install_route port, hw, ip
325
+ # MAC address based routing to instance.
326
+ port.queue_flow "priority=#{1}", "table=#{@@mac_route_table},dl_dst=#{hw}", "output:#{port.port_info.number}"
327
+
328
+ port.queue_flow "priority=#{2}", "table=#{0},in_port=#{port.port_info.number},dl_src=#{hw}", "resubmit(,#{@@route_directly})"
329
+ port.queue_flow "priority=#{1}", "table=#{@@route_directly},dl_dst=#{hw}", "output:#{port.port_info.number}"
330
+
331
+ # @ovs_ofctl.add_flow "priority=#{1},table=#{@@load_dest_table},dl_dst=#{hw}", "load:#{port.port_info.number}->NXM_NX_REG0[],resubmit(,#{@@send_src_table})"
332
+ port.queue_flow "priority=#{1}", "table=#{@@load_dest_table},dl_dst=#{hw}", "drop"
333
+ end
334
+
335
+ def install_virtual_route network, port, hw, ip
336
+ port.queue_flow "priority=#{7}", "table=#{0},in_port=#{port.port_info.number}", "load:#{network.id}->NXM_NX_REG1[],resubmit(,#{@@virtual_src})"
337
+ port.queue_flow "priority=#{2}", "table=#{@@virtual_dest},reg1=#{network.id},dl_dst=#{hw}", "output:#{port.port_info.number}"
338
+ end
339
+
340
+ def install_arp_antispoof port, hw, ip
341
+ # Require correct ARP source IP/MAC from instance, and protect the instance IP from ARP spoofing.
342
+ port.queue_flow "priority=#{3}", "table=#{@@arp_antispoof_table},arp,in_port=#{port.port_info.number},arp_sha=#{hw},nw_src=#{ip}", "resubmit(,#{@@arp_route_table})"
343
+ port.queue_flow "priority=#{2}", "table=#{@@arp_antispoof_table},arp,arp_sha=#{hw}", "drop"
344
+ port.queue_flow "priority=#{2}", "table=#{@@arp_antispoof_table},arp,nw_src=#{ip}", "drop"
345
+
346
+ # Routing of ARP packets to instance.
347
+ port.queue_flow "priority=#{2}", "table=#{@@arp_route_table},arp,dl_dst=#{hw},nw_dst=#{ip}", "output:#{port.port_info.number}"
348
+ end
349
+
350
+ def install_virtual_arp_route network, in_port, hw, ip, out_port, remote_hw, remote_ip
351
+ # Require correct ARP source IP/MAC from instance, and protect the instance IP from ARP spoofing.
352
+ # port.queue_flow "priority=#{4}", "table=#{@@virtual_dest},arp,reg1=#{network.id},arp_sha=#{hw},nw_src=#{ip},dl_dst=#{remote_hw},nw_dst=#{remote_ip}", "output:#{out_port}"
353
+ # port.queue_flow "priority=#{3}", "table=#{@@virtual_dest},arp,arp_sha=#{hw}", "drop"
354
+ # port.queue_flow "priority=#{3}", "table=#{@@virtual_dest},arp,nw_src=#{ip}", "drop"
355
+
356
+ # Make generic...
357
+ add_flow in_port, "priority=#{4}", "table=#{@@virtual_dest},arp,reg1=#{network.id},dl_dst=#{remote_hw},nw_dst=#{remote_ip}", "output:#{out_port}"
358
+
359
+ # Routing of ARP packets to instance.
360
+ add_flow in_port, "priority=#{2}", "table=#{@@arp_route_table},in_port=#{out_port},arp,dl_dst=#{hw},nw_dst=#{ip}", "output:#{in_port}"
361
+ end
362
+
363
+ def install_static_icmp icmp_type, icmp_code, port, local_hw, local_ip, src_ip
364
+ match_type = "dl_type=0x0800,nw_proto=1"
365
+ match_type << ",icmp_type=#{icmp_type}" if icmp_type >= 0
366
+ match_type << ",icmp_code=#{icmp_code}" if icmp_code >= 0
367
+
368
+ src_ip_match = ""
369
+ src_ip_match << ",nw_src=#{src_ip}" if not src_ip =~ /\/0$/
370
+
371
+ incoming_match = "table=#{@@load_dest_table},#{match_type},dl_dst=#{local_hw},nw_dst=#{local_ip}#{src_ip_match}"
372
+ incoming_actions = "load:#{port.port_info.number}->NXM_NX_REG0[],resubmit(,#{@@send_src_table})"
373
+ port.queue_flow "priority=#{3}", incoming_match, incoming_actions
374
+
375
+ outgoing_match = "table=#{@@send_src_table},#{match_type},in_port=#{port.port_info.number},dl_src=#{local_hw},nw_src=#{local_ip}#{src_ip_match},"
376
+ outgoing_actions = "output:NXM_NX_REG0[]"
377
+ port.queue_flow "priority=#{3}", outgoing_match, outgoing_actions
378
+ end
379
+
380
+ def install_static_transport nw_proto, port, local_hw, local_ip, local_port, remote_ip
381
+ match_type = "dl_type=0x0800,nw_proto=#{nw_proto}"
382
+
383
+ src_match = ""
384
+ src_match << ",nw_src=#{remote_ip}" if not remote_ip =~ /\/0$/
385
+ src_match << ",tp_dst=#{local_port}" if local_port != 0
386
+ dst_match = ""
387
+ dst_match << ",nw_dst=#{remote_ip}" if not remote_ip =~ /\/0$/
388
+ dst_match << ",tp_src=#{local_port}" if local_port != 0
389
+
390
+ incoming_match = "table=#{@@load_dest_table},#{match_type},dl_dst=#{local_hw},nw_dst=#{local_ip}#{src_match}"
391
+ incoming_actions = "load:#{port.port_info.number}->NXM_NX_REG0[],resubmit(,#{@@send_src_table})"
392
+ port.queue_flow "priority=#{3}", incoming_match, incoming_actions
393
+
394
+ outgoing_match = "table=#{@@send_src_table},#{match_type},in_port=#{port.port_info.number},dl_src=#{local_hw},nw_src=#{local_ip}#{dst_match}"
395
+ outgoing_actions = "output:NXM_NX_REG0[]"
396
+ port.queue_flow "priority=#{3}", outgoing_match, outgoing_actions
397
+ end
398
+
399
+ def install_static_d_transport nw_proto, port, local_hw, local_ip, remote_ip, remote_port
400
+ match_type = "dl_type=0x0800,nw_proto=#{nw_proto}"
401
+
402
+ src_match = ""
403
+ src_match << ",nw_src=#{remote_ip}" if not remote_ip =~ /\/0$/
404
+ src_match << ",tp_src=#{remote_port}" if remote_port != 0
405
+ dst_match = ""
406
+ dst_match << ",nw_dst=#{remote_ip}" if not remote_ip =~ /\/0$/
407
+ dst_match << ",tp_dst=#{remote_port}" if remote_port != 0
408
+
409
+ incoming_match = "table=#{@@load_dest_table},#{match_type},dl_dst=#{local_hw},nw_dst=#{local_ip}#{src_match}"
410
+ incoming_actions = "load:#{port.port_info.number}->NXM_NX_REG0[],resubmit(,#{@@send_src_table})"
411
+ port.queue_flow "priority=#{3}", incoming_match, incoming_actions
412
+
413
+ outgoing_match = "table=#{@@send_src_table},#{match_type},in_port=#{port.port_info.number},dl_src=#{local_hw},nw_src=#{local_ip}#{dst_match}"
414
+ outgoing_actions = "output:NXM_NX_REG0[]"
415
+ port.queue_flow "priority=#{3}", outgoing_match, outgoing_actions
416
+ end
417
+
418
+ def install_virtual_static_d_transport network, nw_proto, in_port, local_hw, local_ip, out_port, remote_ip, remote_port
419
+ match_type = "dl_type=0x0800,nw_proto=#{nw_proto}"
420
+
421
+ src_match = ""
422
+ src_match << ",nw_src=#{remote_ip}" if not remote_ip =~ /\/0$/
423
+ src_match << ",tp_src=#{remote_port}" if remote_port != 0
424
+ dst_match = ""
425
+ dst_match << ",nw_dst=#{remote_ip}" if not remote_ip =~ /\/0$/
426
+ dst_match << ",tp_dst=#{remote_port}" if remote_port != 0
427
+
428
+ incoming_match = "table=#{@@load_dest_table},#{match_type},dl_dst=#{local_hw},nw_dst=#{local_ip}#{src_match}"
429
+ incoming_actions = "output:#{in_port}"
430
+ add_flow in_port, "priority=#{3}", incoming_match, incoming_actions
431
+
432
+ outgoing_match = "table=#{@@virtual_src},reg1=#{network.id},#{match_type},dl_src=#{local_hw},nw_src=#{local_ip}#{dst_match}"
433
+ outgoing_actions = "output:#{out_port}"
434
+ add_flow in_port, "priority=#{3}", outgoing_match, outgoing_actions
435
+ end
436
+
437
+ def install_local_icmp port, hw, ip
438
+ match_type = "dl_type=0x0800,nw_proto=1"
439
+
440
+ learn_outgoing_match = "priority=#{2},idle_timeout=#{60},table=#{@@load_dest_table},#{match_type},NXM_OF_IN_PORT[],NXM_OF_ETH_SRC[],NXM_OF_ETH_DST[],NXM_OF_IP_SRC[],NXM_OF_IP_DST[]"
441
+ learn_outgoing_actions = "output:NXM_NX_REG0[]"
442
+
443
+ learn_incoming_match = "priority=#{2},idle_timeout=#{60},table=#{@@load_dest_table},#{match_type},NXM_OF_IN_PORT[]=NXM_NX_REG0[0..15],NXM_OF_ETH_SRC[]=NXM_OF_ETH_DST[],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],NXM_OF_IP_SRC[]=NXM_OF_IP_DST[],NXM_OF_IP_DST[]=NXM_OF_IP_SRC[]"
444
+ learn_incoming_actions = "output:NXM_OF_IN_PORT[]"
445
+
446
+ actions = "learn(#{learn_outgoing_match},#{learn_outgoing_actions}),learn(#{learn_incoming_match},#{learn_incoming_actions}),output:NXM_NX_REG0[]"
447
+
448
+ port.queue_flow "priority=#{1}", "table=#{@@send_src_table},#{match_type},in_port=#{port.port_info.number},dl_src=#{hw},nw_src=#{ip}", actions
449
+ end
450
+
451
+ def install_local_transport nw_proto, port, hw, ip
452
+ case nw_proto
453
+ when 6
454
+ transport_name = "TCP"
455
+ idle_timeout = 7200
456
+ when 17
457
+ transport_name = "UDP"
458
+ idle_timeout = 600
459
+ end
460
+
461
+ match_type = "dl_type=0x0800,nw_proto=#{nw_proto}"
462
+
463
+ learn_outgoing_match = "priority=#{2},idle_timeout=#{idle_timeout},table=#{@@load_dest_table},#{match_type},NXM_OF_IN_PORT[],NXM_OF_ETH_SRC[],NXM_OF_ETH_DST[],NXM_OF_IP_SRC[],NXM_OF_IP_DST[],NXM_OF_#{transport_name}_SRC[],NXM_OF_#{transport_name}_DST[]"
464
+ learn_outgoing_actions = "output:NXM_NX_REG0[]"
465
+
466
+ learn_incoming_match = "priority=#{2},idle_timeout=#{idle_timeout},table=#{@@load_dest_table},#{match_type},NXM_OF_IN_PORT[]=NXM_NX_REG0[0..15],NXM_OF_ETH_SRC[]=NXM_OF_ETH_DST[],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],NXM_OF_IP_SRC[]=NXM_OF_IP_DST[],NXM_OF_IP_DST[]=NXM_OF_IP_SRC[],NXM_OF_#{transport_name}_SRC[]=NXM_OF_#{transport_name}_DST[],NXM_OF_#{transport_name}_DST[]=NXM_OF_#{transport_name}_SRC[]"
467
+ learn_incoming_actions = "output:NXM_OF_IN_PORT[]"
468
+
469
+ actions = "learn(#{learn_outgoing_match},#{learn_outgoing_actions}),learn(#{learn_incoming_match},#{learn_incoming_actions}),output:NXM_NX_REG0[]"
470
+
471
+ port.queue_flow "priority=#{1}", "table=#{@@send_src_table},#{match_type},in_port=#{port.port_info.number},dl_src=#{hw},nw_src=#{ip}", actions
472
+ end
473
+
474
+ def install_virtual_network network
475
+ network.flood_flows << ["priority=#{1},table=#{@@virtual_dest},reg1=#{network.id},reg2=#{0},dl_dst=ff:ff:ff:ff:ff:ff", "", "output:<>", ""]
476
+ network.flood_local_flows << ["priority=#{0},table=#{@@virtual_dest},reg1=#{network.id},dl_dst=ff:ff:ff:ff:ff:ff", "", "output:<>", ""]
477
+
478
+ learn_arp_match = "priority=#{1},idle_timeout=#{3600*10},table=#{@@virtual_dest},reg1=#{network.id},reg2=#{0},NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]"
479
+ learn_arp_actions = "output:NXM_NX_REG2[]"
480
+
481
+ @ovs_ofctl.add_flow "priority=#{2},table=#{@@virtual_src},reg1=#{network.id},reg2=#{0}", "resubmit\\(,#{@@virtual_dest}\\)"
482
+ @ovs_ofctl.add_flow "priority=#{1},table=#{@@virtual_src},reg1=#{network.id},arp", "learn\\(#{learn_arp_match},#{learn_arp_actions}\\),resubmit\\(,#{@@virtual_dest}\\)"
483
+ @ovs_ofctl.add_flow "priority=#{0},table=#{@@virtual_src},reg1=#{network.id}", "resubmit\\(,#{@@virtual_dest}\\)"
484
+
485
+ # Catch ARP for the DHCP server.
486
+ @ovs_ofctl.add_flow "priority=#{3},table=#{@@virtual_dest},reg1=#{network.id},arp,nw_dst=#{network.dhcp_ip.to_s}", "controller"
487
+
488
+ # Catch DHCP requests.
489
+ @ovs_ofctl.add_flow "priority=#{3},table=#{@@virtual_dest},reg1=#{network.id},udp,dl_dst=#{network.dhcp_hw},nw_dst=#{network.dhcp_ip.to_s},tp_src=68,tp_dst=67", "controller"
490
+ @ovs_ofctl.add_flow "priority=#{3},table=#{@@virtual_dest},reg1=#{network.id},udp,dl_dst=ff:ff:ff:ff:ff:ff,nw_dst=255.255.255.255,tp_src=68,tp_dst=67", "controller"
491
+
492
+ logger.info "installed virtual network: id:#{network.id} dhcp_hw:#{network.dhcp_hw} dhcp_ip:#{network.dhcp_ip.to_s}."
493
+ end
494
+
495
+ def install_physical_network network
496
+ network.flood_flows << ["priority=#{1},table=#{@@mac_route_table},dl_dst=FF:FF:FF:FF:FF:FF", "", "output:<>", ""]
497
+ network.flood_flows << ["priority=#{1},table=#{@@route_directly},dl_dst=FF:FF:FF:FF:FF:FF", "", "output:<>", ""]
498
+ network.flood_flows << ["priority=#{1},table=#{@@load_dest_table},dl_dst=FF:FF:FF:FF:FF:FF", "", "load:<>->NXM_NX_REG0[],resubmit(,#{@@send_src_table})", ""]
499
+ network.flood_flows << ["priority=#{1},table=#{@@arp_route_table},arp,dl_dst=FF:FF:FF:FF:FF:FF,arp_tha=00:00:00:00:00:00", "", "output:<>", ""]
500
+ end
501
+
502
+ def install_gre_tunnel network_id, port
503
+ port.is_tunnel = true
504
+ port.queue_flow "priority=#{7}", "table=#{0},in_port=#{port.port_info.number}", "load:#{network_id}->NXM_NX_REG1[],load:#{port.port_info.number}->NXM_NX_REG2[],resubmit(,#{@@virtual_src})"
505
+ end
506
+
507
+ def install_eth port
508
+ port_number = port.port_info.number
509
+
510
+ port.queue_flow "priority=#{6}", "udp,in_port=local,dl_dst=ff:ff:ff:ff:ff:ff,nw_src=0.0.0.0,nw_dst=255.255.255.255,tp_src=68,tp_dst=67", "output:#{port_number}"
511
+ port.queue_flow "priority=#{2}", "in_port=#{port_number}", "resubmit(,#{@@route_directly})"
512
+ port.queue_flow "priority=#{0}", "table=#{@@mac_route_table}", "output:#{port_number}"
513
+ port.queue_flow "priority=#{0}", "table=#{@@route_directly}", "output:#{port_number}"
514
+ port.queue_flow "priority=#{0}", "table=#{@@load_dest_table}", "load:#{port_number}->NXM_NX_REG0[],resubmit(,#{@@send_src_table})"
515
+ port.queue_flow "priority=#{4}", "table=#{@@send_src_table},in_port=#{port_number}", "output:NXM_NX_REG0[]"
516
+ port.queue_flow "priority=#{1}", "table=#{@@arp_antispoof_table},arp,in_port=#{port_number}", "resubmit(,#{@@arp_route_table})"
517
+ port.queue_flow "priority=#{0}", "table=#{@@arp_route_table},arp", "output:#{port_number}"
518
+ port.queue_flow "priority=#{4}", "table=#{@@metadata_outgoing_table},in_port=#{port_number}", "drop"
519
+ end
520
+
521
+ def update_network network
522
+ @ovs_ofctl.add_flows_from_list network.generate_flood_flows
523
+ end
524
+
525
+ def send_udp datapath_id, out_port, src_hw, src_ip, src_port, dst_hw, dst_ip, dst_port, payload
526
+ raw_out = Racket::Racket.new
527
+ raw_out.l2 = Racket::L2::Ethernet.new
528
+ raw_out.l2.src_mac = src_hw
529
+ raw_out.l2.dst_mac = dst_hw
530
+
531
+ raw_out.l3 = Racket::L3::IPv4.new
532
+ raw_out.l3.src_ip = src_ip
533
+ raw_out.l3.dst_ip = dst_ip
534
+ raw_out.l3.protocol = 0x11
535
+
536
+ raw_out.l4 = Racket::L4::UDP.new
537
+ raw_out.l4.src_port = src_port
538
+ raw_out.l4.dst_port = dst_port
539
+ raw_out.l4.payload = payload
540
+
541
+ raw_out.l4.fix!(raw_out.l3.src_ip, raw_out.l3.dst_ip)
542
+
543
+ raw_out.layers.compact.each { |l|
544
+ logger.debug "send udp: layer:#{l.pretty}."
545
+ }
546
+
547
+ send_packet_out(datapath_id, :data => raw_out.pack, :actions => Trema::ActionOutput.new( :port => out_port ) )
548
+ end
549
+
550
+ def send_arp datapath_id, out_port, op_code, src_hw, src_ip, dst_hw, dst_ip
551
+ raw_out = Racket::Racket.new
552
+ raw_out.l2 = Racket::L2::Ethernet.new
553
+ raw_out.l2.ethertype = Racket::L2::Ethernet::ETHERTYPE_ARP
554
+ raw_out.l2.src_mac = src_hw
555
+ raw_out.l2.dst_mac = dst_hw
556
+
557
+ raw_out.l3 = Racket::L3::ARP.new
558
+ raw_out.l3.opcode = op_code
559
+ raw_out.l3.sha = src_hw
560
+ raw_out.l3.spa = src_ip
561
+ raw_out.l3.tha = dst_hw
562
+ raw_out.l3.tpa = dst_ip
563
+
564
+ raw_out.layers.compact.each { |l|
565
+ logger.debug "ARP packet: layer:#{l.pretty}."
566
+ }
567
+
568
+ send_packet_out(datapath_id, :data => raw_out.pack, :actions => Trema::ActionOutput.new( :port => out_port ) )
569
+ end
570
+
571
+ end
572
+
573
+
574
+ class OvsOfctl
575
+ include Dcmgr::Logger
576
+ attr_accessor :ovs_ofctl
577
+ attr_accessor :verbose
578
+
579
+ def initialize config
580
+ # TODO: Make ovs_vsctl use a real config option.
581
+ @ovs_ofctl = config.ovs_ofctl_path
582
+ @ovs_vsctl = config.ovs_ofctl_path.dup
583
+ @ovs_vsctl[/ovs-ofctl/] = 'ovs-vsctl'
584
+
585
+ @switch = config.bridge_novlan
586
+ @verbose = config.verbose_openflow
587
+ end
588
+
589
+ def add_flow flow_match, actions
590
+ command = "#{@ovs_ofctl} add-flow #{@switch} #{flow_match},actions=#{actions}"
591
+ logger.debug "'#{command}' => #{system(command)}."
592
+ end
593
+
594
+ def del_flow flow_match
595
+ command = "#{@ovs_ofctl} del-flows #{@switch} #{flow_match}"
596
+ logger.debug "'#{command}' => #{system(command)}."
597
+ end
598
+
599
+ def add_flows_from_list(flows)
600
+ recmds = []
601
+
602
+ eos = "__EOS_#{Isono::Util.gen_id}___"
603
+ recmds << "#{@ovs_ofctl} add-flow #{@switch} - <<'#{eos}'"
604
+ flows.each { |flow|
605
+ full_flow = "#{flow[0]},actions=#{flow[1]}"
606
+ puts "ovs-ofctl add-flow #{@switch} #{full_flow}" if verbose == true
607
+ recmds << full_flow
608
+ }
609
+ recmds << "#{eos}"
610
+
611
+ logger.debug("applying flow(s): #{recmds.size - 2}")
612
+ system(recmds.join("\n"))
613
+ end
614
+
615
+ def del_flows_from_list(flows)
616
+ recmds = []
617
+
618
+ eos = "__EOS_#{Isono::Util.gen_id}___"
619
+ recmds << "#{@ovs_ofctl} del-flows #{@switch} - <<'#{eos}'"
620
+ flows.each { |flow|
621
+ puts "ovs-ofctl del-flows #{@switch} #{flow}" if verbose == true
622
+ recmds << flow
623
+ }
624
+ recmds << "#{eos}"
625
+
626
+ logger.debug("removing flow(s): #{recmds.size - 2}")
627
+ system(recmds.join("\n"))
628
+ end
629
+
630
+ def arg_in_port port_number
631
+ case port_number
632
+ when OpenFlowController::OFPP_LOCAL
633
+ return "in_port=local"
634
+ else
635
+ return "in_port=#{port_number}" if port_number < OpenFlowController::OFPP_MAX
636
+ end
637
+ end
638
+
639
+ def arg_output port_number
640
+ case port_number
641
+ when OpenFlowController::OFPP_LOCAL
642
+ return "local"
643
+ else
644
+ return "output:#{port_number}" if port_number < OpenFlowController::OFPP_MAX
645
+ end
646
+ end
647
+
648
+ def add_gre_tunnel tunnel_name, remote_ip, key
649
+ system("#{@ovs_vsctl} add-port #{@switch} #{tunnel_name} -- set interface #{tunnel_name} type=gre options:remote_ip=#{remote_ip} options:key=#{key}")
650
+ end
651
+
652
+ end
653
+
654
+ class OpenFlowPort
655
+ attr_reader :port_info
656
+ attr_reader :lock
657
+ attr_accessor :has_instance
658
+ attr_accessor :is_active
659
+ attr_accessor :is_tunnel
660
+ attr_accessor :ip
661
+ attr_accessor :mac
662
+ attr_accessor :network
663
+
664
+ def initialize port_info
665
+ @port_info = port_info
666
+ @lock = Mutex.new
667
+ @has_instance = false
668
+ @is_active = false
669
+ @is_tunnel = false
670
+ end
671
+
672
+ def active_flows
673
+ @active_flows ||= Array.new
674
+ end
675
+
676
+ def queued_flows
677
+ @queued_flows ||= Array.new
678
+ end
679
+
680
+ def queue_flow prefix, match, actions
681
+ active_flows << match
682
+ queued_flows << ["#{prefix},#{match}", actions]
683
+ end
684
+ end
685
+
686
+ class OpenFlowForwardingEntry
687
+ attr_reader :mac
688
+ attr_reader :port_no
689
+
690
+ def initialize mac, port_no
691
+ @mac = mac
692
+ @port_no = port_no
693
+ end
694
+
695
+ def update port_no
696
+ @port_no = port_no
697
+ end
698
+ end
699
+
700
+ class OpenFlowForwardingDatabase
701
+ def initialize
702
+ @db = {}
703
+ end
704
+
705
+ def port_no_of mac
706
+ dest = @db[mac]
707
+
708
+ if dest
709
+ dest.port_no
710
+ else
711
+ nil
712
+ end
713
+ end
714
+
715
+ def learn mac, port_no
716
+ entry = @db[mac]
717
+
718
+ if entry
719
+ entry.update port_no
720
+ else
721
+ @db[new_entry.mac] = ForwardingEntry.new(mac, port_no)
722
+ end
723
+ end
724
+ end
725
+
726
+ class OpenFlowNetwork
727
+ attr_reader :id
728
+ attr_reader :ports
729
+ attr_reader :local_ports
730
+ attr_accessor :virtual
731
+ attr_accessor :dhcp_hw
732
+ attr_accessor :dhcp_ip
733
+ attr_accessor :ipv4_network
734
+ attr_accessor :prefix
735
+
736
+ def initialize id
737
+ @id = id
738
+ @ports = []
739
+ @local_ports = []
740
+ @virtual = false
741
+ @prefix = 0
742
+ end
743
+
744
+ def add_port port, is_local
745
+ ports << port
746
+ local_ports << port if is_local
747
+ end
748
+
749
+ def remove_port port
750
+ ports.delete port
751
+ local_ports.delete port
752
+ end
753
+
754
+ def generate_flood_flows
755
+ flows = []
756
+ flood_flows.each { |flow|
757
+ flows << [flow[0], "#{flow[1]}#{generate_flood_actions(flow[2], ports)}#{flow[3]}"]
758
+ }
759
+ flood_local_flows.each { |flow|
760
+ flows << [flow[0], "#{flow[1]}#{generate_flood_actions(flow[2], local_ports)}#{flow[3]}"]
761
+ }
762
+ flows
763
+ end
764
+
765
+ def generate_flood_actions template, use_ports
766
+ actions = ""
767
+ use_ports.each { |port|
768
+ actions << ",#{template.gsub('<>', port.to_s)}"
769
+ }
770
+ actions
771
+ end
772
+
773
+ def flood_flows
774
+ @flood_flows ||= Array.new
775
+ end
776
+
777
+ def flood_local_flows
778
+ @flood_local_flows ||= Array.new
779
+ end
780
+
781
+ end
782
+
783
+ end
784
+ end