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.
- data/Rakefile +19 -31
- data/bin/collector +6 -1
- data/config/db/migrations/0001_v1110_origin.rb +446 -0
- data/config/dcmgr.conf.example +51 -0
- data/lib/dcmgr.rb +99 -22
- data/lib/dcmgr/cli/base.rb +34 -1
- data/lib/dcmgr/cli/host.rb +24 -20
- data/lib/dcmgr/cli/image.rb +38 -19
- data/lib/dcmgr/cli/keypair.rb +16 -12
- data/lib/dcmgr/cli/network.rb +189 -81
- data/lib/dcmgr/cli/quota.rb +2 -2
- data/lib/dcmgr/cli/security_group.rb +106 -0
- data/lib/dcmgr/cli/spec.rb +144 -39
- data/lib/dcmgr/cli/storage.rb +16 -15
- data/lib/dcmgr/cli/tag.rb +20 -14
- data/lib/dcmgr/cli/vlan.rb +5 -5
- data/lib/dcmgr/drivers/backing_store.rb +32 -0
- data/lib/dcmgr/drivers/comstar.rb +81 -0
- data/lib/dcmgr/drivers/iijgio_storage.rb +9 -19
- data/lib/dcmgr/drivers/iscsi_target.rb +41 -0
- data/lib/dcmgr/drivers/kvm.rb +161 -28
- data/lib/dcmgr/drivers/linux_iscsi.rb +60 -0
- data/lib/dcmgr/drivers/local_storage.rb +24 -0
- data/lib/dcmgr/drivers/lxc.rb +167 -125
- data/lib/dcmgr/drivers/raw.rb +74 -0
- data/lib/dcmgr/drivers/s3_storage.rb +7 -19
- data/lib/dcmgr/drivers/snapshot_storage.rb +18 -28
- data/lib/dcmgr/drivers/storage_initiator.rb +28 -0
- data/lib/dcmgr/drivers/sun_iscsi.rb +32 -0
- data/lib/dcmgr/drivers/zfs.rb +77 -0
- data/lib/dcmgr/endpoints/core_api.rb +315 -263
- data/lib/dcmgr/endpoints/errors.rb +21 -10
- data/lib/dcmgr/endpoints/metadata.rb +360 -23
- data/lib/dcmgr/helpers/cli_helper.rb +6 -3
- data/lib/dcmgr/helpers/ec2_metadata_helper.rb +9 -0
- data/lib/dcmgr/helpers/nic_helper.rb +11 -0
- data/lib/dcmgr/helpers/snapshot_storage_helper.rb +34 -0
- data/lib/dcmgr/models/account.rb +0 -6
- data/lib/dcmgr/models/account_resource.rb +0 -4
- data/lib/dcmgr/models/base_new.rb +14 -2
- data/lib/dcmgr/models/dhcp_range.rb +38 -0
- data/lib/dcmgr/models/frontend_system.rb +0 -6
- data/lib/dcmgr/models/history.rb +0 -11
- data/lib/dcmgr/models/host_node.rb +131 -0
- data/lib/dcmgr/models/hostname_lease.rb +0 -8
- data/lib/dcmgr/models/image.rb +31 -18
- data/lib/dcmgr/models/instance.rb +137 -143
- data/lib/dcmgr/models/instance_nic.rb +52 -29
- data/lib/dcmgr/models/instance_security_group.rb +9 -0
- data/lib/dcmgr/models/instance_spec.rb +163 -31
- data/lib/dcmgr/models/ip_lease.rb +10 -21
- data/lib/dcmgr/models/mac_lease.rb +30 -11
- data/lib/dcmgr/models/network.rb +148 -27
- data/lib/dcmgr/models/physical_network.rb +18 -0
- data/lib/dcmgr/models/quota.rb +0 -10
- data/lib/dcmgr/models/request_log.rb +3 -18
- data/lib/dcmgr/models/security_group.rb +66 -0
- data/lib/dcmgr/models/security_group_rule.rb +145 -0
- data/lib/dcmgr/models/ssh_key_pair.rb +16 -19
- data/lib/dcmgr/models/{storage_pool.rb → storage_node.rb} +35 -25
- data/lib/dcmgr/models/tag.rb +0 -14
- data/lib/dcmgr/models/tag_mapping.rb +1 -7
- data/lib/dcmgr/models/vlan_lease.rb +2 -8
- data/lib/dcmgr/models/volume.rb +49 -37
- data/lib/dcmgr/models/volume_snapshot.rb +15 -17
- data/lib/dcmgr/node_modules/hva_collector.rb +69 -28
- data/lib/dcmgr/node_modules/instance_ha.rb +23 -12
- data/lib/dcmgr/node_modules/instance_monitor.rb +16 -2
- data/lib/dcmgr/node_modules/openflow_controller.rb +784 -0
- data/lib/dcmgr/node_modules/scheduler.rb +189 -0
- data/lib/dcmgr/node_modules/service_netfilter.rb +452 -227
- data/lib/dcmgr/node_modules/service_openflow.rb +731 -0
- data/lib/dcmgr/node_modules/sta_collector.rb +20 -0
- data/lib/dcmgr/node_modules/sta_tgt_initializer.rb +35 -0
- data/lib/dcmgr/rack/request_logger.rb +11 -6
- data/lib/dcmgr/rpc/hva_handler.rb +256 -110
- data/lib/dcmgr/rpc/sta_handler.rb +244 -0
- data/lib/dcmgr/scheduler.rb +122 -8
- data/lib/dcmgr/scheduler/host_node/exclude_same.rb +24 -0
- data/lib/dcmgr/scheduler/host_node/find_first.rb +12 -0
- data/lib/dcmgr/scheduler/host_node/least_usage.rb +28 -0
- data/lib/dcmgr/scheduler/host_node/per_instance.rb +18 -0
- data/lib/dcmgr/scheduler/host_node/specify_node.rb +26 -0
- data/lib/dcmgr/scheduler/network/flat_single.rb +23 -0
- data/lib/dcmgr/scheduler/network/nat_one_to_one.rb +23 -0
- data/lib/dcmgr/scheduler/network/per_instance.rb +39 -0
- data/lib/dcmgr/scheduler/network/vif_template.rb +19 -0
- data/lib/dcmgr/scheduler/storage_node/find_first.rb +13 -0
- data/lib/dcmgr/scheduler/storage_node/least_usage.rb +23 -0
- data/lib/dcmgr/storage_service.rb +39 -40
- data/lib/dcmgr/tags.rb +3 -3
- data/lib/dcmgr/version.rb +1 -1
- data/lib/dcmgr/vnet.rb +105 -0
- data/lib/dcmgr/vnet/factories.rb +141 -0
- data/lib/dcmgr/vnet/isolators/by_securitygroup.rb +21 -0
- data/lib/dcmgr/vnet/isolators/dummy.rb +17 -0
- data/lib/dcmgr/vnet/netfilter/cache.rb +51 -0
- data/lib/dcmgr/vnet/netfilter/chain.rb +66 -0
- data/lib/dcmgr/vnet/netfilter/controller.rb +193 -0
- data/lib/dcmgr/vnet/netfilter/ebtables_rule.rb +53 -0
- data/lib/dcmgr/vnet/netfilter/iptables_rule.rb +45 -0
- data/lib/dcmgr/vnet/netfilter/task_manager.rb +459 -0
- data/lib/dcmgr/vnet/tasks/accept_all_dns.rb +19 -0
- data/lib/dcmgr/vnet/tasks/accept_arp_broadcast.rb +24 -0
- data/lib/dcmgr/vnet/tasks/accept_arp_from_friends.rb +34 -0
- data/lib/dcmgr/vnet/tasks/accept_arp_from_gateway.rb +21 -0
- data/lib/dcmgr/vnet/tasks/accept_arp_to_host.rb +30 -0
- data/lib/dcmgr/vnet/tasks/accept_ip_from_friends.rb +26 -0
- data/lib/dcmgr/vnet/tasks/accept_ip_from_gateway.rb +23 -0
- data/lib/dcmgr/vnet/tasks/accept_ip_to_anywhere.rb +18 -0
- data/lib/dcmgr/vnet/tasks/accept_related_established.rb +45 -0
- data/lib/dcmgr/vnet/tasks/accept_wakame_dhcp_only.rb +33 -0
- data/lib/dcmgr/vnet/tasks/accept_wakame_dns_only.rb +33 -0
- data/lib/dcmgr/vnet/tasks/debug_iptables.rb +21 -0
- data/lib/dcmgr/vnet/tasks/drop_arp_forwarding.rb +27 -0
- data/lib/dcmgr/vnet/tasks/drop_arp_to_host.rb +24 -0
- data/lib/dcmgr/vnet/tasks/drop_ip_from_anywhere.rb +18 -0
- data/lib/dcmgr/vnet/tasks/drop_ip_spoofing.rb +34 -0
- data/lib/dcmgr/vnet/tasks/drop_mac_spoofing.rb +33 -0
- data/lib/dcmgr/vnet/tasks/exclude_from_nat.rb +47 -0
- data/lib/dcmgr/vnet/tasks/security_group.rb +37 -0
- data/lib/dcmgr/vnet/tasks/static_nat.rb +54 -0
- data/lib/dcmgr/vnet/tasks/translate_metadata_address.rb +32 -0
- data/web/metadata/config.ru +1 -1
- metadata +174 -89
- data/lib/dcmgr/cli/group.rb +0 -101
- data/lib/dcmgr/endpoints/core_api_mock.rb +0 -865
- data/lib/dcmgr/models/host_pool.rb +0 -122
- data/lib/dcmgr/models/instance_netfilter_group.rb +0 -16
- data/lib/dcmgr/models/netfilter_group.rb +0 -89
- data/lib/dcmgr/models/netfilter_rule.rb +0 -21
- data/lib/dcmgr/scheduler/find_last.rb +0 -16
- data/lib/dcmgr/scheduler/find_random.rb +0 -16
- data/lib/dcmgr/stm/instance.rb +0 -25
- data/lib/dcmgr/stm/snapshot_context.rb +0 -33
- 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
|
-
|
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
|