diff --git a/lib/ovsdb.ex b/lib/ovsdb.ex deleted file mode 100644 index 7a4c9d0..0000000 --- a/lib/ovsdb.ex +++ /dev/null @@ -1,22 +0,0 @@ -defmodule OVSDB do - @moduledoc false - - @behaviour :supervisor - - def start_link do - :supervisor.start_link({:local, __MODULE__}, __MODULE__, []) - end - - def init([]) do - child = OVSDB.OpenvSwitch - strategy = :simple_one_for_one - max_r = 1000 - intensity = 3600 - sup_flags = {strategy, max_r, intensity} - {:ok, {sup_flags, [{child, {child, :start_link, []}, :temporary, 1000, :worker, [child]}]}} - end - - def start_child(server) do - :supervisor.start_child(__MODULE__, [server]) - end -end diff --git a/lib/ovsdb/open_vswitch.ex b/lib/ovsdb/open_vswitch.ex deleted file mode 100644 index 530c670..0000000 --- a/lib/ovsdb/open_vswitch.ex +++ /dev/null @@ -1,414 +0,0 @@ -defmodule OVSDB.OpenvSwitch do - use GenServer - - defmodule State do - defstruct server: nil, - client_pid: nil, - monitor_pid: nil, - ovs_uuid: nil - end - - @database "Open_vSwitch" - - @open_vswitch "Open_vSwitch" - @interface "Interface" - @port "Port" - @controller "Controller" - @bridge "Bridge" - - def find_by_name(pid, table, name) do - GenServer.call(pid, {:find_by_name, table, name}) - end - - # 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"}) - - add_br_options = [ - bridge: options[:name], - fail_mode: options[:fail_mode] || "standalone", - datapath_id: options[:datapath_id], - disable_in_band: options[:disable_in_band], - br_uuids: br_uuids - ] - - GenServer.call(pid, {:add_br, add_br_options}) - end - - @doc """ - Delete a bridge - - iex> OpenvSwitch.del_br(client_pid, "br0") - """ - def del_br(pid, bridge) do - case find_by_name(pid, @bridge, bridge) do - %{"_uuid" => uuid} -> - new_bridges = - case GenServer.call(pid, {:sync_get, @open_vswitch, "bridges"}) do - ["set", bridges] -> %{"bridges" => ["set", bridges -- [uuid]]} - ^uuid -> %{"bridges" => ["set", []]} - curr_bridges -> %{"bridges" => curr_bridges} - end - - GenServer.call(pid, {:del_br, new_bridges}) - - :not_found -> - {:error, :not_found} - 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 - state = - server - |> String.to_charlist() - |> init_client - - {:ok, state} - end - - def handle_call({:sync_get, table, col_name}, _from, state) do - [%{"rows" => [%{^col_name => values} | _]}] = - [col_name] - |> :eovsdb_op.select(table, []) - |> xact(state.client_pid) - - {:reply, values, state} - end - - def handle_call({:add_br, options}, _from, state) do - %State{client_pid: pid, ovs_uuid: ovs} = state - br_iface = %{name: options[:bridge], type: :internal} - br_port = %{name: options[:bridge], interfaces: ["named-uuid", "interface"]} - - 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 = %{ - name: options[:bridge], - ports: ["named-uuid", "port"], - fail_mode: options[:fail_mode], - other_config: make_ovsdb_map(other_config) - } - - named_uuid = ["named-uuid", "bridge"] - new_bridges = %{bridges: add_elem_to_set(options[:br_uuids], named_uuid)} - - next_config = [{"next_cfg", "+=", 1}] - eq_ovs_uuid = [{"_uuid", "==", ovs}] - - replies = - xact( - [ - :eovsdb_op.insert(@interface, br_iface, "interface"), - :eovsdb_op.insert(@port, br_port, "port"), - :eovsdb_op.insert(@bridge, new_bridge, "bridge"), - :eovsdb_op.update(@open_vswitch, eq_ovs_uuid, new_bridges), - :eovsdb_op.mutate(@open_vswitch, eq_ovs_uuid, next_config) - ], - pid - ) - - {:reply, replies, state} - end - - def handle_call({:del_br, new_bridges}, _from, state) do - %State{client_pid: pid, ovs_uuid: ovs} = state - eq_ovs_uuid = [{"_uuid", "==", ovs}] - next_config = [{"next_cfg", "+=", 1}] - - replies = - xact( - [ - :eovsdb_op.update(@open_vswitch, eq_ovs_uuid, new_bridges), - :eovsdb_op.mutate(@open_vswitch, eq_ovs_uuid, next_config) - ], - pid - ) - - {:reply, replies, state} - end - - def handle_call({:del_port, options}, _from, state) do - %State{client_pid: pid, ovs_uuid: ovs} = state - eq_br_name = [{"name", "==", options[:bridge]}] - eq_ovs_uuid = [{"_uuid", "==", ovs}] - next_config = [{"next_cfg", "+=", 1}] - - bridge = %{ports: options[:ports]} - - replies = - xact( - [ - :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({: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} - end - - def handle_cast({:async_get, "_uuid"}, state) do - [%{"rows" => [%{"_uuid" => values} | _]}] = - ["_uuid"] - |> :eovsdb_op.select(@open_vswitch, []) - |> xact(state.client_pid) - - {:noreply, %{state | ovs_uuid: values}} - end - - # private functions - - defp init_client(server) do - {:ok, pid} = :eovsdb_client.connect(server, database: @database) - :eovsdb_client.regist_schema(pid) - :ok = GenServer.cast(self(), {:async_get, "_uuid"}) - %State{server: server, client_pid: pid} - end - - defp xact(query, pid) when is_list(query) do - {:ok, res} = :eovsdb_client.transaction(pid, query) - res - end - - defp xact(query, pid) when is_map(query) do - xact([query], pid) - 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 diff --git a/lib/tres/application.ex b/lib/tres/application.ex index 462e22c..7bed3f0 100644 --- a/lib/tres/application.ex +++ b/lib/tres/application.ex @@ -12,8 +12,7 @@ defmodule Tres.Application do children = [ worker(Registry, [[keys: :unique, name: SwitchRegistry]], id: SwitchRegistry), worker(Registry, [[keys: :unique, name: HandlerRegistry]], id: HandlerRegistry), - supervisor(Tres.MessageHandlerSup, [], id: MessageHandlerSup), - supervisor(OVSDB, [], id: OVSDB) + supervisor(Tres.MessageHandlerSup, [], id: MessageHandlerSup) ] opts = [strategy: :one_for_one, name: Tres.Supervisor] diff --git a/test/lib/ovsdb/openvswitch_test.exs b/test/lib/ovsdb/openvswitch_test.exs deleted file mode 100644 index d28f0ba..0000000 --- a/test/lib/ovsdb/openvswitch_test.exs +++ /dev/null @@ -1,44 +0,0 @@ -defmodule OVSDB.OpenvSwitchTest do - use ExUnit.Case, async: false - - setup_all do - {:ok, pid} = OVSDB.start_child("127.0.0.1:6640") - {:ok, pid: pid} - end - - describe "OVSDB.OpenvSwitch.find_by_name/3" do - test "with pid, table and name", context do - %{"datapath_id" => "0000000000000001"} = OVSDB.OpenvSwitch.find_by_name(context.pid, "Bridge", "br0") - end - end - - describe "OVSDB.OpenvSwitch.add_br/2" do - test "with options", context do - OVSDB.OpenvSwitch.add_br( - context.pid, - name: "brx", - datapath_id: "0000000000000003" - ) - end - end - - describe "OVSDB.OpenvSwitch.set_controller/2" do - test "with options", context do - OVSDB.OpenvSwitch.add_br( - context.pid, - name: "brx", - target: "tcp:127.0.0.1:6653", - connection_mode: "out-of-band", - controller_rate_limit: 100, - controller_burst_limit: 25, - protocol: "OpenFlow13" - ) - end - end - - describe "OVSDB.OpenvSwitch.del_br/2" do - test "with pid and name", context do - OVSDB.OpenvSwitch.del_br(context.pid, "brx") - end - end -end