Add patch_panel example
This commit is contained in:
parent
b16cafbb5c
commit
51729542f3
12 changed files with 227 additions and 0 deletions
4
examples/patch_panel/.formatter.exs
Normal file
4
examples/patch_panel/.formatter.exs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
||||
24
examples/patch_panel/.gitignore
vendored
Normal file
24
examples/patch_panel/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where 3rd-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
# Also ignore archive artifacts (built via "mix archive.build").
|
||||
*.ez
|
||||
|
||||
# Ignore package tarball (built via "mix hex.build").
|
||||
patch_panel-*.tar
|
||||
|
||||
16
examples/patch_panel/README.md
Normal file
16
examples/patch_panel/README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# PatchPanel
|
||||
|
||||
openflow controller that emulates a software patch panel
|
||||
|
||||
## prerequisites
|
||||
|
||||
- Erlang 20 or higher
|
||||
- Elixir 1.6.1 or higher
|
||||
- OpenFlow switch supports version 1.3
|
||||
|
||||
```iex
|
||||
# To add a patch link
|
||||
iex > :ok = PatchPanel.Openflow.Controller.create_patch("de780562fb45, 1, 2)
|
||||
# To delete a patch link
|
||||
iex > :ok = PatchPanel.Openflow.Controller.delete_patch("de780562fb45, 1, 2)
|
||||
```
|
||||
7
examples/patch_panel/config/config.exs
Normal file
7
examples/patch_panel/config/config.exs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# This file is responsible for configuring your application
|
||||
# and its dependencies with the aid of the Mix.Config module.
|
||||
use Mix.Config
|
||||
|
||||
config :tres,
|
||||
callback_module: PatchPanel.Openflow.Controller,
|
||||
callback_args: []
|
||||
18
examples/patch_panel/lib/patch_panel.ex
Normal file
18
examples/patch_panel/lib/patch_panel.ex
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
defmodule PatchPanel do
|
||||
@moduledoc """
|
||||
Documentation for PatchPanel.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Hello world.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> PatchPanel.hello
|
||||
:world
|
||||
|
||||
"""
|
||||
def hello do
|
||||
:world
|
||||
end
|
||||
end
|
||||
20
examples/patch_panel/lib/patch_panel/application.ex
Normal file
20
examples/patch_panel/lib/patch_panel/application.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
defmodule PatchPanel.Application do
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
alias PatchPanel.Openflow
|
||||
|
||||
def start(_type, _args) do
|
||||
import Supervisor.Spec
|
||||
|
||||
children = [
|
||||
worker(Registry, [[keys: :unique, name: Openflow.Registry]], id: Openflow.Registry),
|
||||
]
|
||||
|
||||
opts = [strategy: :one_for_one, name: PatchPanel.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
end
|
||||
81
examples/patch_panel/lib/patch_panel/openflow/controller.ex
Normal file
81
examples/patch_panel/lib/patch_panel/openflow/controller.ex
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
defmodule PatchPanel.Openflow.Controller do
|
||||
use GenServer
|
||||
use Tres.Controller
|
||||
|
||||
import Logger
|
||||
|
||||
defmodule State do
|
||||
defstruct [:datapath_id]
|
||||
end
|
||||
|
||||
def create_patch(datapath_id, port_a, port_b) do
|
||||
case PatchPanel.Openflow.Registry.lookup_pid(datapath_id) do
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
pid when is_pid(pid) ->
|
||||
GenServer.call(pid, {:create, port_a, port_b})
|
||||
end
|
||||
end
|
||||
|
||||
def delete_patch(datapath_id, port_a, port_b) do
|
||||
case PatchPanel.Openflow.Registry.lookup_pid(datapath_id) do
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
pid when is_pid(pid) ->
|
||||
GenServer.call(pid, {:delete, port_a, port_b})
|
||||
end
|
||||
end
|
||||
|
||||
def start_link({datapath_id, _aux_id}, _start_args) do
|
||||
GenServer.start_link(__MODULE__, [datapath_id])
|
||||
end
|
||||
|
||||
def init([datapath_id]) do
|
||||
:ok = info("Switch Connected: datapath_id = #{datapath_id}")
|
||||
{:ok, _} = PatchPanel.Openflow.Registry.register(datapath_id)
|
||||
{:ok, %State{datapath_id: datapath_id}}
|
||||
end
|
||||
|
||||
def handle_call({:create, port_a, port_b}, _from, %State{datapath_id: datapath_id} = state) do
|
||||
:ok = add_flow_entries(datapath_id, port_a, port_b)
|
||||
{:reply, :ok, state}
|
||||
end
|
||||
def handle_call({:delete, port_a, port_b}, _from, %State{datapath_id: datapath_id} = state) do
|
||||
:ok = del_flow_entries(datapath_id, port_a, port_b)
|
||||
{:reply, :ok, state}
|
||||
end
|
||||
|
||||
def handle_info({:switch_disconnected, reason}, %State{datapath_id: datapath_id} = state) do
|
||||
:ok = warn("#{datapath_id} disconnected: reason = #{inspect(reason)}")
|
||||
:ok = PatchPanel.Openflow.Registry.unregister(datapath_id)
|
||||
{:stop, :normal, state}
|
||||
end
|
||||
def handle_info(_info, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def terminate(reason, state) do
|
||||
{reason, state}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp add_flow_entries(datapath_id, port_a, port_b) do
|
||||
:ok = send_flow_mod_add(
|
||||
datapath_id,
|
||||
match: Match.new(in_port: port_a),
|
||||
instructions: [ApplyActions.new(Output.new(port_b))]
|
||||
)
|
||||
|
||||
:ok = send_flow_mod_add(
|
||||
datapath_id,
|
||||
match: Match.new(in_port: port_b),
|
||||
instructions: [ApplyActions.new(Output.new(port_a))]
|
||||
)
|
||||
end
|
||||
|
||||
defp del_flow_entries(datapath_id, port_a, port_b) do
|
||||
:ok = send_flow_mod_delete(datapath_id, match: Match.new(in_port: port_a))
|
||||
:ok = send_flow_mod_delete(datapath_id, match: Match.new(in_port: port_b))
|
||||
end
|
||||
end
|
||||
16
examples/patch_panel/lib/patch_panel/openflow/registry.ex
Normal file
16
examples/patch_panel/lib/patch_panel/openflow/registry.ex
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
defmodule PatchPanel.Openflow.Registry do
|
||||
def register(datapath_id) do
|
||||
{:ok, _} = Registry.register(__MODULE__, datapath_id, [])
|
||||
end
|
||||
|
||||
def unregister(datapath_id) do
|
||||
:ok = Registry.unregister(__MODULE__, datapath_id)
|
||||
end
|
||||
|
||||
def lookup_pid(datapath_id) do
|
||||
case Registry.lookup(__MODULE__, datapath_id) do
|
||||
[{pid, _}] -> pid
|
||||
[] -> nil
|
||||
end
|
||||
end
|
||||
end
|
||||
26
examples/patch_panel/mix.exs
Normal file
26
examples/patch_panel/mix.exs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule PatchPanel.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :patch_panel,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.6",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps()
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger],
|
||||
mod: {PatchPanel.Application, []}
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[{:tres, path: "../../../tres"}]
|
||||
end
|
||||
end
|
||||
6
examples/patch_panel/mix.lock
Normal file
6
examples/patch_panel/mix.lock
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
%{
|
||||
"eovsdb": {:git, "https://github.com/shun159/eovsdb.git", "1ff1572708d72fd25631c681f2102407903252a3", [branch: "master"]},
|
||||
"jsone": {:git, "https://github.com/sile/jsone.git", "eecc9666c7165e1870b78a7a762549ae8d1c391b", [tag: "1.2.1"]},
|
||||
"ranch": {:hex, :ranch, "1.4.0", "10272f95da79340fa7e8774ba7930b901713d272905d0012b06ca6d994f8826b", [:rebar3], [], "hexpm"},
|
||||
"uuid": {:git, "https://github.com/avtobiff/erlang-uuid.git", "585c2474afb4a597ae8c8bf6d21e5a9c73f18e0b", [tag: "v0.5.0"]},
|
||||
}
|
||||
8
examples/patch_panel/test/patch_panel_test.exs
Normal file
8
examples/patch_panel/test/patch_panel_test.exs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
defmodule PatchPanelTest do
|
||||
use ExUnit.Case
|
||||
doctest PatchPanel
|
||||
|
||||
test "greets the world" do
|
||||
assert PatchPanel.hello() == :world
|
||||
end
|
||||
end
|
||||
1
examples/patch_panel/test/test_helper.exs
Normal file
1
examples/patch_panel/test/test_helper.exs
Normal file
|
|
@ -0,0 +1 @@
|
|||
ExUnit.start()
|
||||
Loading…
Add table
Add a link
Reference in a new issue