Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ PATH
specs:
phut (0.7.7)
activesupport (~> 4.2.6)
ffi-yajl (~> 2.2.3)
gli (~> 2.13.4)
pio (~> 0.30.0)
pry (~> 0.10.3)
yajl-ruby (~> 1.2.1)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -69,6 +71,8 @@ GEM
faker (1.6.3)
i18n (~> 0.5)
ffi (1.9.10)
ffi-yajl (2.2.3)
libyajl2 (~> 1.2)
flay (2.8.0)
erubis (~> 2.7.0)
path_expander (~> 1.0)
Expand Down Expand Up @@ -113,6 +117,7 @@ GEM
i18n (0.7.0)
ice_nine (0.11.2)
json (1.8.3)
libyajl2 (1.2.0)
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
Expand All @@ -133,6 +138,7 @@ GEM
pio (0.30.0)
activesupport (~> 4.2, >= 4.2.4)
bindata (~> 2.1.0)
bundler (~> 1.11.2)
powerpack (0.1.1)
pry (0.10.3)
coderay (~> 1.1.0)
Expand Down Expand Up @@ -205,6 +211,7 @@ GEM
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
yajl-ruby (1.2.1)
yard (0.8.7.6)

PLATFORMS
Expand Down
17 changes: 10 additions & 7 deletions features/shell/vswitch#ports.feature
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ Feature: Vswitch#ports
Scenario: Vswitch#ports #=> []
When I type "vswitch.ports"
And sleep 5
Then the output should contain "[]"
Then the output should contain:
"""
#<Port device: "vsw_0xabc", number: 65534>
"""

@sudo
Scenario: Vswitch#ports
Expand All @@ -20,9 +23,9 @@ Feature: Vswitch#ports
When I type "vswitch.ports"
And sleep 5
Then the output should contain:
"""
["L0_a"]
"""
"""
#<Port device: "L0_a", number: 1>
"""

@sudo
Scenario: Vswitch#ports
Expand All @@ -31,6 +34,6 @@ Feature: Vswitch#ports
When I type "vswitch.ports"
And sleep 5
Then the output should contain:
"""
["L0_a"]
"""
"""
#<Port device: "L0_a", number: 2>
"""
1 change: 1 addition & 0 deletions lib/phut.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
require 'phut/version'
require 'phut/vhost_daemon'
require 'phut/vswitch'
require 'phut/ovsdb'
1 change: 1 addition & 0 deletions lib/phut/open_vswitch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def <=>(other)
private

def start
@vsctl.set_manager
@vsctl.add_bridge
@vsctl.set_openflow_version_and_dpid
@vsctl.controller_tcp_port = @tcp_port
Expand Down
7 changes: 7 additions & 0 deletions lib/phut/ovsdb.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'phut/ovsdb/client'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing frozen string literal comment.

require 'phut/ovsdb/transact'

module Phut
# OVSDB client core
module OVSDB; end
end
100 changes: 100 additions & 0 deletions lib/phut/ovsdb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@

Primitive OVSDB client implementation
===

Supports [RFC7047](https://tools.ietf.org/html/rfc7047).

## Examples

### Transaction

* Create Bridge

```ruby
require 'active_flow'

class OVSDBTest
extend ActiveFlow::OVSDB::Transact

def self.create_bridge(name, ofc_target, bridge_options = {})
client = ActiveFlow::OVSDB::Client.new('localhost', 6632)
ovs_rows_query = select('Open_vSwitch', [], [:_uuid, :bridges])
ovs_row = client.transact(1, 'Open_vSwitch', [ovs_rows_query]).first[:rows].first
ovs_bridges = ovs_row[:bridges]
new_ovs_bridges = case ovs_bridges.include?('set')
when true
ovs_bridges_content = ovs_bridges[1]
case ovs_bridges_content.empty?
when true
['named-uuid', "bridge_br_#{name}"]
else
['set', ovs_bridges_content << ['named-uuid', "bridge_br_#{name}"]]
end
else
ovs_bridges_content = ovs_bridges[1]
['set', [ovs_bridges_content] << ['named-uuid', "bridge_br_#{name}"]]
end
ovs_uuid = ovs_row[:_uuid]
interface = { name: "br-#{name}", type: "internal" }
port = { name: "br-#{name}", interfaces: ['named-uuid', "interface_br_#{name}"] }
controller = { target: ofc_target }
bridge = { name: "br-#{name}", ports: ['named-uuid', "port_br_#{name}"], controller: ['named-uuid', "ofc_br_#{name}"], protocols: 'OpenFlow10' }
transactions = [
insert('Interface', interface, "interface_br_#{name}"),
insert('Port', port, "port_br_#{name}"),
insert('Controller', controller, "ofc_br_#{name}"),
insert('Bridge', bridge, "bridge_br_#{name}"),
update('Open_vSwitch', [[:_uuid, :==, ovs_uuid]], { bridges: new_ovs_bridges }),
mutate('Open_vSwitch', [[:_uuid, :==, ovs_uuid]], [[:next_cfg, '+=', 1]])
]
client.transact(1, 'Open_vSwitch', transactions)
transactions = [
update('Bridge', [[:name, :==, "br-#{name}"]], { other_config: [:map, bridge_options.to_a] }),
mutate('Open_vSwitch', [[:_uuid, :==, ovs_uuid]], [[:next_cfg, '+=', 1]])
]
client.transact(1, 'Open_vSwitch', transactions)
end

def self.connect_with_patch(br1, br2)
patch_br1 = "patch-#{br1}"
patch_br2 = "patch-#{br2}"
client = ActiveFlow::OVSDB::Client.new('localhost', 6632)
ovs_rows_query = select('Open_vSwitch', [], [:_uuid])
ovs_row = client.transact(1, 'Open_vSwitch', [ovs_rows_query]).first[:rows].first
ovs_uuid = ovs_row[:_uuid]
selects = [
select('Bridge', [[:name, :==, br1]], [:ports]),
select('Bridge', [[:name, :==, br2]], [:ports])
]
br1_ports, br2_ports = client.transact(1, 'Open_vSwitch', selects)
new_br1_ports = br1_ports.map do |_, item|
ports = item[0][:ports].include?('set') ? item[0][:ports][1] : [item[0][:ports]]
[:set, ports << ['named-uuid', :patch_br1]]
end.first
new_br2_ports = br2_ports.map do |_, item|
ports = item[0][:ports].include?('set') ? item[0][:ports][1] : [item[0][:ports]]
[:set, ports << ['named-uuid', :patch_br2]]
end.first

patch_br1_port = {name: patch_br1, interfaces: ['named-uuid', :patch_br1_iface]}
patch_br2_port = {name: patch_br2, interfaces: ['named-uuid', :patch_br2_iface]}

patch_br1_iface = {name: patch_br1, type: :patch, options: [:map, {peer: patch_br2}.to_a]}
patch_br2_iface = {name: patch_br2, type: :patch, options: [:map, {peer: patch_br1}.to_a]}

transactions = [
insert('Interface', patch_br1_iface, :patch_br1_iface),
insert('Interface', patch_br2_iface, :patch_br2_iface),
insert('Port', patch_br1_port, :patch_br1),
insert('Port', patch_br2_port, :patch_br2),
update('Bridge', [[:name, :==, br1]], { ports: new_br1_ports }),
update('Bridge', [[:name, :==, br2]], { ports: new_br2_ports }),
mutate('Open_vSwitch', [[:_uuid, :==, ovs_uuid]], [[:next_cfg, '+=', 1]])
]
client.transact(1, 'Open_vSwitch', transactions)
end
end

# OVSDBTest.create_bridge('def', 'tcp:127.0.0.1:6653', 'datapath-id' => '0000000000000def')
# OVSDBTest.connect_with_patch('nts0xabc', 'br-def')
```
74 changes: 74 additions & 0 deletions lib/phut/ovsdb/client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
require 'phut/ovsdb/method'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing frozen string literal comment.

require 'phut/ovsdb/transport'
require 'yajl'

module Phut
module OVSDB
# OVSDB Client core
class Client
include Phut::OVSDB::Method

attr_reader :transport
attr_reader :database

def initialize(host, port, options = {})
@mut = Mutex.new
@queue = Queue.new
@transport = Transport.new(host, port, self, options)
@database = options.fetch(:database, nil)
initialize_codec
end

def handle_tcp(data)
@parser << data
end

def handle_message(data)
case data[:method]
when 'echo'
echo_reply
else
maybe_handle_reply(data)
end
end

private

def maybe_handle_reply(data)
id = data[:id]
case id
when 'echo'
:noop
else
@queue.enq(data)
end
end

def initialize_codec
@parser = Yajl::Parser.new(symbolize_keys: true)
@parser.on_parse_complete = method(:handle_message)
@encoder = Yajl::Encoder.new
end

def json_async_send(jsonable)
json_data = @encoder.encode(jsonable)
transport.send(json_data)
end

def json_send(jsonable)
json_async_send(jsonable)
th = Thread.new do
result = nil
continue = true
while continue
next if @queue.empty?
@mut.synchronize { result = @queue.deq }
continue = false
end
result
end
th.join.value
end
end
end
end
77 changes: 77 additions & 0 deletions lib/phut/ovsdb/method.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
require 'e2mmap'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing frozen string literal comment.


module Phut
module OVSDB
# OVSDB methods
module Method
extend Exception2MessageMapper

def_exception :GetSchemaError, '%s'
def_exception :TransactionError, '%s'

def echo(id, params = [])
data = json_send(id: id, method: 'echo', params: params)
data[:result]
end

def echo_reply
json_async_send(id: 'echo', result: [], error: nil)
end

def list_dbs(id)
data = json_send(id: id, method: 'list_dbs', params: [])
data[:result]
end

def get_schema(id, db_name = @database)
data = json_send(
id: id,
method: 'get_schema',
params: Array(db_name)
)
error = data[:error]
if error
raise(GetSchemaError, get_schema_errmsg(error))
else
data[:result]
end
end

def transact(id, db_name, operations)
data = json_send(
id: id,
method: 'transact',
params: [db_name, *operations]
)
data[:result]
end

def cancel(id, params)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回のポート一覧に関係のないメソッドは、この PR ではすべて削ってコンパクトにしてください。ポート一覧のほかにも OVSDB 必要な箇所をイロイロみつけたので、その時に削った部分を復活しましょう!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

しょうちしました。

end

def monitor(id, params)
end

def update(id, params)
end

def monitor_cancel(id, params)
end

def lock(id, params)
end

def steal(id, params)
end

def unlock(id, params)
end

private

def get_schema_errmsg(error)
"error: #{error[:error]}, details: #{error[:details]}"
end
end
end
end
Loading