ovsdb: Add functions that I often use

This commit is contained in:
Eishun Kondoh 2018-08-16 15:38:03 +09:00
parent 927241b3f4
commit d555cd8e09
2 changed files with 256 additions and 28 deletions

Binary file not shown.

View file

@ -16,28 +16,43 @@ defmodule OVSDB.OpenvSwitch do
@controller "Controller" @controller "Controller"
@bridge "Bridge" @bridge "Bridge"
def start_link(server) do
GenServer.start_link(__MODULE__, [server])
end
def find_by_name(pid, table, name) do def find_by_name(pid, table, name) do
GenServer.call(pid, {:find_by_name, table, name}) GenServer.call(pid, {:find_by_name, table, name})
end end
def add_br(pid, bridge, options \\ []) do # API functions
@doc """
Create a bridge:
## options:
iex> OpenvSwitch.add_br(
client_pid,
name: "br0",
fail_mode: "standalone",
datapath_id: "0000000000000001",
disable_in_band: "true"
)
"""
def add_br(pid, [_|_] = options) do
br_uuids = GenServer.call(pid, {:sync_get, @open_vswitch, "bridges"}) br_uuids = GenServer.call(pid, {:sync_get, @open_vswitch, "bridges"})
add_br_options = [ add_br_options = [
bridge: bridge, bridge: options[:name],
controller: options[:controller] || "tcp:127.0.0.1:6653",
protocol: options[:protocol] || "OpenFlow13",
fail_mode: options[:fail_mode] || "standalone", fail_mode: options[:fail_mode] || "standalone",
datapath_id: options[:datapath_id],
disable_in_band: options[:disable_in_band],
br_uuids: br_uuids br_uuids: br_uuids
] ]
GenServer.call(pid, {:add_br, add_br_options}) GenServer.call(pid, {:add_br, add_br_options})
end end
@doc """
Delete a bridge
iex> OpenvSwitch.del_br(client_pid, "br0")
"""
def del_br(pid, bridge) do def del_br(pid, bridge) do
case find_by_name(pid, @bridge, bridge) do case find_by_name(pid, @bridge, bridge) do
%{"_uuid" => uuid} -> %{"_uuid" => uuid} ->
@ -55,6 +70,109 @@ defmodule OVSDB.OpenvSwitch do
end end
end end
@doc """
Set a controller to the switch
iex> OpenvSwitch.set_controller(
client_pid,
bridge: "br0",
target: "tcp:127.0.0.1:6653",
connection_mode: "out-of-band",
controller_rate_limit: 100,
controller_burst_limit: 25,
protocol: "OpenFlow13"
)
"""
def set_controller(pid, [_|_] = options) do
case find_by_name(pid, @bridge, options[:bridge]) do
:not_found ->
{:error, :not_found}
%{"_uuid" => _uuid} ->
set_ctl_opts = [
bridge: options[:bridge],
target: options[:target] || "tcp:127.0.0.1:6653",
connection_mode: options[:connection_mode] || "out-of-band",
controller_rate_limit: options[:controller_rate_limit] || 1000,
controller_burst_limit: options[:controller_burst_limit] || 100,
protocol: options[:protocol] || "OpenFlow13",
]
GenServer.call(pid, {:set_controller, set_ctl_opts})
end
end
@doc """
iex> OpenvSwitch.add_port(
client_pid,
bridge: "br0",
name: "vxlan5",
type: "vxlan",
remote_ip: "flow",
ofport_request: 99
)
"""
def add_port(pid, [_|_] = options) do
case find_by_name(pid, @bridge, options[:bridge]) do
:not_found ->
{:error, :not_found}
%{"_uuid" => _uuid, "ports" => ports} ->
port_opts = [
bridge: options[:bridge],
name: options[:name],
type: options[:type] || "system",
ofport_request: options[:ofport_request],
remote_ip: options[:remote_ip],
local_ip: options[:local_ip],
in_key: options[:in_key],
out_key: options[:out_key],
key: options[:key],
tos: options[:tos],
ttl: options[:ttl],
df_default: options[:df_default],
csum: options[:csum],
peer_cert: options[:peer_cert],
certificate: options[:certificate],
private_key: options[:private_key],
psk: options[:psk],
ingress_policing_rate: options[:ingress_policing_rate] || 0,
ingress_policing_burst: options[:ingress_policing_burst] || 0,
ports: ports
]
GenServer.call(pid, {:add_port, port_opts})
end
end
@doc """
iex> OpenvSwitch.del_port(client_pid, bridge: "br0", port: "vxlan5")
"""
def del_port(pid, [_|_] = options) do
case find_by_name(pid, @bridge, options[:bridge]) do
:not_found ->
{:error, :not_found}
%{"_uuid" => _uuid, "ports" => ports} ->
case find_by_name(pid, @port, options[:port]) do
:not_found ->
{:error, :not_found}
%{"_uuid" => port_uuid} ->
new_ports = del_elem_from_set(ports, port_uuid)
port_opts = [
bridge: options[:bridge],
ports: new_ports
]
GenServer.call(pid, {:del_port, port_opts})
end
end
end
# GenServer callback functions
def start_link(server) do
GenServer.start_link(__MODULE__, [server])
end
def init([server]) do def init([server]) do
state = state =
server server
@ -77,25 +195,24 @@ defmodule OVSDB.OpenvSwitch do
%State{client_pid: pid, ovs_uuid: ovs} = state %State{client_pid: pid, ovs_uuid: ovs} = state
br_iface = %{name: options[:bridge], type: :internal} br_iface = %{name: options[:bridge], type: :internal}
br_port = %{name: options[:bridge], interfaces: ["named-uuid", "brinterface"]} br_port = %{name: options[:bridge], interfaces: ["named-uuid", "brinterface"]}
controller = %{target: options[:controller]}
other_config = [
["datapath-id", options[:datapath_id]],
["dp-desc", options[:dp_desc]],
["disable-in-band", options[:disable_in_band]],
["in-band-queue", options[:in_band_queue]]
]
new_bridge = %{ new_bridge = %{
name: options[:bridge], name: options[:bridge],
ports: ["named-uuid", "brport"], ports: ["named-uuid", "brport"],
controller: ["named-uuid", "brcontroller"],
fail_mode: options[:fail_mode], fail_mode: options[:fail_mode],
protocols: options[:protocol] other_config: make_ovsdb_map(other_config)
} }
named_uuid = ["named-uuid", "bridge"] named_uuid = ["named-uuid", "bridge"]
new_bridges = new_bridges = add_elem_to_set(options[:br_uuids], named_uuid)
case options[:br_uuids] do
["set", []] -> %{bridges: named_uuid}
["set", bridges] -> %{bridges: ["set", bridges ++ [named_uuid]]}
["uuid", _] = bridge -> %{bridges: ["set", [bridge] ++ [named_uuid]]}
end
next_config = [{"next_cfg", "+=", 1}] next_config = [{"next_cfg", "+=", 1}]
eq_ovs_uuid = [{"_uuid", "==", ovs}] eq_ovs_uuid = [{"_uuid", "==", ovs}]
@ -104,7 +221,6 @@ defmodule OVSDB.OpenvSwitch do
[ [
:eovsdb_op.insert(@interface, br_iface, "brinterface"), :eovsdb_op.insert(@interface, br_iface, "brinterface"),
:eovsdb_op.insert(@port, br_port, "brport"), :eovsdb_op.insert(@port, br_port, "brport"),
:eovsdb_op.insert(@controller, controller, "brcontroller"),
:eovsdb_op.insert(@bridge, new_bridge, "bridge"), :eovsdb_op.insert(@bridge, new_bridge, "bridge"),
:eovsdb_op.update(@open_vswitch, eq_ovs_uuid, new_bridges), :eovsdb_op.update(@open_vswitch, eq_ovs_uuid, new_bridges),
:eovsdb_op.mutate(@open_vswitch, eq_ovs_uuid, next_config) :eovsdb_op.mutate(@open_vswitch, eq_ovs_uuid, next_config)
@ -132,16 +248,103 @@ defmodule OVSDB.OpenvSwitch do
{:reply, replies, state} {:reply, replies, state}
end end
def handle_call({:find_by_name, table, name}, _from, state) do def handle_call({:del_port, options}, _from, state) do
%State{client_pid: pid} = state %State{client_pid: pid, ovs_uuid: ovs} = state
query = :eovsdb_op.select('*', table, [{"name", "==", name}]) eq_br_name = [{"name", "==", options[:bridge]}]
eq_ovs_uuid = [{"_uuid", "==", ovs}]
next_config = [{"next_cfg", "+=", 1}]
reply = bridge = %{ports: options[:ports]}
case xact(query, pid) do
[%{"rows" => []}] -> :not_found replies =
[%{"rows" => [row]}] -> row xact([
:eovsdb_op.update(@bridge, eq_br_name, bridge),
:eovsdb_op.mutate(@open_vswitch, eq_ovs_uuid, next_config)
], pid)
{:reply, replies, state}
end end
def handle_call({:set_controller, options}, _from, state) do
%State{client_pid: pid, ovs_uuid: ovs} = state
controller = %{
target: options[:target],
connection_mode: options[:connection_mode],
controller_rate_limit: options[:controller_rate_limit],
controller_burst_limit: options[:controller_burst_limit],
}
bridge = %{
protocols: options[:protocol],
controller: ["named-uuid", "controller"],
}
replies =
xact([
:eovsdb_op.insert(@controller, controller, "controller"),
:eovsdb_op.update(@bridge, [{"name", "==", options[:bridge]}], bridge),
:eovsdb_op.mutate(@open_vswitch, [{"_uuid", "==", ovs}], [{"next_cfg", "+=", 1}])
], pid)
{:reply, replies, state}
end
def handle_call({:add_port, options}, _from, state) do
%State{client_pid: pid, ovs_uuid: ovs} = state
port = %{
name: options[:name],
interfaces: ["named-uuid", "interface"],
}
iface_options = [
["remote_ip", options[:remote_ip]],
["local_ip", options[:local_ip]],
["in_key", options[:in_key]],
["out_key", options[:out_key]],
["key", options[:key]],
["tos", options[:tos]],
["ttl", options[:ttl]],
["df_default", options[:df_default]],
["csum", options[:csum]],
["peer_cert", options[:peer_cert]],
["certificate", options[:certificate]],
["private_key", options[:private_key]],
["psk", options[:psk]]
]
interface = %{
name: options[:name],
type: options[:type],
ingress_policing_rate: options[:ingress_policing_rate],
ingress_policing_burst: options[:ingress_policing_burst],
ofport_request: make_ovsdb_set(options[:ofport_request]),
options: make_ovsdb_map(iface_options)
}
bridge = %{ports: add_elem_to_set(options[:ports], ["named-uuid", "port"])}
next_config = [{"next_cfg", "+=", 1}]
eq_br_name = [{"name", "==", options[:bridge]}]
eq_ovs_uuid = [{"_uuid", "==", ovs}]
replies =
xact(
[
:eovsdb_op.insert(@interface, interface, "interface"),
:eovsdb_op.insert(@port, port, "port"),
:eovsdb_op.update(@bridge, eq_br_name, bridge),
:eovsdb_op.mutate(@open_vswitch, eq_ovs_uuid, next_config)
],
pid
)
{:reply, replies, state}
end
def handle_call({:find_by_name, table, name}, _from, state) do
%State{client_pid: pid} = state
reply = do_find_by_name(pid, table, name)
{:reply, reply, state} {:reply, reply, state}
end end
@ -171,4 +374,29 @@ defmodule OVSDB.OpenvSwitch do
defp xact(query, pid) when is_map(query) do defp xact(query, pid) when is_map(query) do
xact([query], pid) xact([query], pid)
end end
defp do_find_by_name(pid, table, name) do
query = :eovsdb_op.select('*', table, [{"name", "==", name}])
case xact(query, pid) do
[%{"rows" => []}] -> :not_found
[%{"rows" => [row]}] -> row
end
end
defp make_ovsdb_map(map), do: make_ovsdb_map([], map)
defp make_ovsdb_map(acc, []), do: ["map", Enum.reverse(acc)]
defp make_ovsdb_map(acc, [[_key, nil]|rest]), do: make_ovsdb_map(acc, rest)
defp make_ovsdb_map(acc, [attr|rest]), do: make_ovsdb_map([attr|acc], rest)
defp make_ovsdb_set(nil), do: ["set", []]
defp make_ovsdb_set([_|_] = list), do: ["set", list]
defp make_ovsdb_set(value), do: value
defp add_elem_to_set(["set", []], value), do: value
defp add_elem_to_set(["set", values], value), do: ["set", values ++ value]
defp add_elem_to_set(["uuid", _] = uuid, value), do: ["set", [uuid] ++ [value]]
defp del_elem_from_set(["set", values], value), do: ["set", values -- [value]]
defp del_elem_from_set(["uuid", _], _value), do: ["set", []]
end end