Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use OVSDB client in order to retrive port list #41

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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:
"""
[]
"""

@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 number: 1, device: "L0_a">]
"""

@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 number: 2, device: "L0_a">]
"""
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/transaction'

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
26 changes: 26 additions & 0 deletions lib/phut/ovsdb/method.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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_reply
json_async_send(id: 'echo', result: [], error: nil)
end

def transact(id, db_name, operations)
data = json_send(
id: id,
method: 'transact',
params: [db_name, *operations]
)
data[:result]
end
end
end
end
92 changes: 92 additions & 0 deletions lib/phut/ovsdb/transaction.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
module Phut

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 OVSDB
# Transaction
module Transaction
def select(table, conds, cols = nil)
select = {
op: :select,
table: table,
where: Array(conds)
}
select = { columns: Array(cols) }.merge(select) if cols
select
end

def insert(table, row, uuid_name = nil)
insert = {
op: :insert,
table: table,
row: row
}
insert = { 'uuid-name' => uuid_name }.merge(insert) if uuid_name
insert
end

def update(table, conds, row)
{
op: :update,
table: table,
where: Array(conds),
row: row
}
end

def delete(table, conds)
{
op: :delete,
table: table,
where: Array(conds)
}
end

def mutate(table, conds, mutes)
{
op: :mutate,
table: table,
where: Array(conds),
mutations: Array(mutes)
}
end

def commit(mode = true)
{
op: :commit,
durable: mode
}
end

def abort
{
op: :abort
}
end

def wait(table, cond, cols, until_cond, rows, timeout = nil)
wait = {
op: :wait,
table: table,
where: Array(cond),
columns: Array(cols),
until: until_cond,
rows: Array(rows)
}
wait = { timeout: timeout }.merge(wait) if timeout
wait
end

def comment(string)
{
op: :comment,
comment: string
}
end

def assert(lock_id)
{
op: :assert,
lock: lock_id
}
end
end
end
end
Loading