Fix to handler start_link fail
This commit is contained in:
parent
0df6336f5e
commit
658b7448da
17 changed files with 17 additions and 2012 deletions
250
test/flay.ex
250
test/flay.ex
|
|
@ -1,250 +0,0 @@
|
|||
defmodule Flay do
|
||||
use GenServer
|
||||
use Tres.Controller
|
||||
|
||||
import Logger
|
||||
|
||||
defmodule State do
|
||||
defstruct datapath_id: nil,
|
||||
tester_pid: nil,
|
||||
conn_ref: nil,
|
||||
reply_to: nil,
|
||||
default_profile: nil
|
||||
end
|
||||
|
||||
def start_link(datapath, args) do
|
||||
GenServer.start_link(__MODULE__, [datapath, args], name: __MODULE__)
|
||||
end
|
||||
|
||||
def init(args) do
|
||||
state = init_controller(args)
|
||||
GenServer.cast(Flay, :desc_stats)
|
||||
GenServer.cast(Flay, :flow_del)
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
def handle_call(:port_desc_stats, from, state) do
|
||||
send_message(PortDesc.Request.new(), state.datapath_id)
|
||||
{:noreply, %{state | reply_to: from}}
|
||||
end
|
||||
|
||||
def handle_call(:flow_stats, from, state) do
|
||||
send_message(Flow.Request.new(), state.datapath_id)
|
||||
{:noreply, %{state | reply_to: from}}
|
||||
end
|
||||
|
||||
def handle_cast(:desc_stats, state) do
|
||||
send_message(Desc.Request.new(), state.datapath_id)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_cast({:register_pid, tester_pid}, state) do
|
||||
{:noreply, %{state | tester_pid: tester_pid}}
|
||||
end
|
||||
|
||||
def handle_cast({:flow_install, flow_opts, tester_pid}, state) do
|
||||
send_flow_mod_add(state.datapath_id, flow_opts)
|
||||
flow_opts_to_ofp_print(flow_opts)
|
||||
{:noreply, %{state | tester_pid: tester_pid}}
|
||||
end
|
||||
|
||||
def handle_cast(:flow_del, state) do
|
||||
send_flow_mod_delete(state.datapath_id)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_cast({:flow_del, cookie}, state) do
|
||||
send_flow_mod_delete(state.datapath_id, cookie: cookie, cookie_mask: 0xFFFFFFFFFFFFFFFF)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(%ErrorMsg{} = error, state) do
|
||||
send(state.tester_pid, error)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(%PacketIn{} = pktin, state) do
|
||||
send(state.tester_pid, pktin)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(%TableFeatures.Reply{} = table, state) do
|
||||
{:noreply, %{state | default_profile: table}}
|
||||
end
|
||||
|
||||
def handle_info(%PortDesc.Reply{} = desc, state) do
|
||||
GenServer.reply(state.reply_to, desc)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(%Desc.Reply{} = desc, state) do
|
||||
info(
|
||||
"[#{__MODULE__}] Switch Desc: " <>
|
||||
"mfr = #{desc.mfr_desc} " <> "hw = #{desc.hw_desc} " <> "sw = #{desc.sw_desc} "
|
||||
)
|
||||
|
||||
init_bridge(state.datapath_id, desc)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(%Flow.Reply{} = desc, state) do
|
||||
GenServer.reply(state.reply_to, desc)
|
||||
{:noreply, %{state | reply_to: nil}}
|
||||
end
|
||||
|
||||
# `Catch all` function is required.
|
||||
def handle_info(info, state) do
|
||||
:ok = warn("[#{__MODULE__}] unhandled message #{inspect(info)}")
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp flow_opts_to_ofp_print(flow_opts) do
|
||||
flow_opts
|
||||
|> FlowMod.new()
|
||||
|> Openflow.to_binary()
|
||||
|> binary_to_space_delimited_hex
|
||||
|> ofp_print_cmd
|
||||
|> Logger.info()
|
||||
end
|
||||
|
||||
defp ofp_print_cmd(print_args) do
|
||||
{result, _code} = System.cmd("ovs-ofctl", ["ofp-print", "#{print_args}"])
|
||||
result
|
||||
end
|
||||
|
||||
defp binary_to_space_delimited_hex(binary) do
|
||||
binary
|
||||
|> split_to_hex_string
|
||||
|> Enum.join(" ")
|
||||
|> String.downcase()
|
||||
end
|
||||
|
||||
defp split_to_hex_string(binary) do
|
||||
for <<int <- binary>>, do: integer_to_hex(int)
|
||||
end
|
||||
|
||||
defp integer_to_hex(int) do
|
||||
case Integer.to_string(int, 16) do
|
||||
<<d>> -> <<48, d>>
|
||||
dd -> dd
|
||||
end
|
||||
end
|
||||
|
||||
defp init_controller([datapath_id, tester_pid]) do
|
||||
conn_ref = SwitchRegistry.monitor(datapath_id)
|
||||
|
||||
%State{
|
||||
datapath_id: datapath_id,
|
||||
tester_pid: tester_pid,
|
||||
conn_ref: conn_ref
|
||||
}
|
||||
end
|
||||
|
||||
defp init_bridge(datapath_id, %Desc.Reply{mfr_desc: "Aruba"}) do
|
||||
:ok = info("Transform flow table pipeline")
|
||||
|
||||
tables = [
|
||||
TableFeatures.Body.new(
|
||||
table_id: 0,
|
||||
name: "classifier",
|
||||
max_entries: 50,
|
||||
config: [:table_miss_mask],
|
||||
match: [
|
||||
:in_port,
|
||||
:eth_type,
|
||||
:eth_src,
|
||||
:masked_eth_dst,
|
||||
:ip_proto,
|
||||
:vlan_vid,
|
||||
:ipv4_src,
|
||||
:udp_dst,
|
||||
:tcp_dst
|
||||
],
|
||||
wildcards: [
|
||||
:in_port,
|
||||
:eth_src,
|
||||
:eth_type,
|
||||
:masked_eth_dst,
|
||||
:vlan_vid,
|
||||
:ip_proto,
|
||||
:ipv4_src,
|
||||
:udp_dst,
|
||||
:tcp_dst
|
||||
],
|
||||
instructions: [
|
||||
Openflow.Instruction.GotoTable,
|
||||
Openflow.Instruction.ApplyActions
|
||||
],
|
||||
apply_actions: [
|
||||
Openflow.Action.Output,
|
||||
Openflow.Action.PushVlan,
|
||||
Openflow.Action.PopVlan,
|
||||
Openflow.Action.SetField
|
||||
],
|
||||
apply_setfield: [
|
||||
:eth_dst,
|
||||
:vlan_vid
|
||||
],
|
||||
next_tables: [
|
||||
1
|
||||
]
|
||||
),
|
||||
TableFeatures.Body.new(
|
||||
table_id: 1,
|
||||
name: "admission_control",
|
||||
max_entries: 50,
|
||||
config: [:table_miss_mask],
|
||||
match: [
|
||||
:eth_type,
|
||||
:eth_src,
|
||||
:masked_eth_dst,
|
||||
:vlan_vid,
|
||||
:ip_proto,
|
||||
:udp_dst,
|
||||
:tcp_dst,
|
||||
:ipv4_src,
|
||||
:ipv4_dst
|
||||
],
|
||||
wildcards: [
|
||||
:eth_type,
|
||||
:eth_src,
|
||||
:masked_eth_dst,
|
||||
:vlan_vid,
|
||||
:ip_proto,
|
||||
:udp_dst,
|
||||
:tcp_dst,
|
||||
:ipv4_src,
|
||||
:ipv4_dst
|
||||
],
|
||||
instructions: [
|
||||
Openflow.Instruction.GotoTable,
|
||||
Openflow.Instruction.ApplyActions
|
||||
],
|
||||
apply_actions: [
|
||||
Openflow.Action.Output,
|
||||
Openflow.Action.PushVlan,
|
||||
Openflow.Action.PopVlan,
|
||||
Openflow.Action.SetField
|
||||
],
|
||||
apply_setfield: [
|
||||
:eth_dst,
|
||||
:vlan_vid,
|
||||
:ipv4_src,
|
||||
:ipv4_dst
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
TableFeatures.Request.new(tables)
|
||||
|> send_message(datapath_id)
|
||||
|
||||
send_flow_mod_delete(datapath_id, table_id: :all)
|
||||
end
|
||||
|
||||
defp init_bridge(_datapath_id, _mfr) do
|
||||
:ok = info("Flow pipeline profile is not defined")
|
||||
:ok
|
||||
end
|
||||
end
|
||||
1166
test/flog_test.exs
1166
test/flog_test.exs
File diff suppressed because it is too large
Load diff
77
test/pf.ex
77
test/pf.ex
|
|
@ -1,77 +0,0 @@
|
|||
defmodule Pf do
|
||||
use GenServer
|
||||
|
||||
import Record
|
||||
# Extract Erlang record for msantos/pkt
|
||||
for {name, schema} <- extract_all(from_lib: "pkt/include/pkt.hrl") do
|
||||
defrecord(name, schema)
|
||||
end
|
||||
|
||||
defmodule State do
|
||||
defstruct ifname: nil,
|
||||
pcap_ref: nil,
|
||||
tester_pid: nil
|
||||
end
|
||||
|
||||
def inject!(pid, packet, payload \\ "") do
|
||||
GenServer.cast(pid, {:inject, {packet, payload}})
|
||||
end
|
||||
|
||||
def stop(pid) do
|
||||
GenServer.cast(pid, :stop)
|
||||
end
|
||||
|
||||
def start_link(ifname) do
|
||||
ifname = String.to_charlist(ifname)
|
||||
GenServer.start_link(__MODULE__, [ifname, self()])
|
||||
end
|
||||
|
||||
def init([ifname, tester_pid]) do
|
||||
{:ok, init_pf(ifname, tester_pid)}
|
||||
end
|
||||
|
||||
def handle_cast({:inject, {headers, payload}}, state) do
|
||||
headers_bin =
|
||||
for header <- headers do
|
||||
case header do
|
||||
ether() -> :pkt.ether(header)
|
||||
{:"802.1q", _, _, _, _} = vlan -> :pkt_802_1q.codec(vlan)
|
||||
arp() -> :pkt.arp(header)
|
||||
ipv4() -> :pkt.ipv4(header)
|
||||
lldp() -> :pkt.lldp(header)
|
||||
udp() -> :pkt.udp(header)
|
||||
tcp() -> :pkt.tcp(header)
|
||||
end
|
||||
end
|
||||
|
||||
binary = Enum.join(headers_bin, "")
|
||||
:epcap.send(state.pcap_ref, <<binary::bytes, payload::bytes>>)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_cast(:stop, state) do
|
||||
{:stop, :normal, state}
|
||||
end
|
||||
|
||||
def handle_cast(_req, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info({:packet, _dlt, _time, _len, data}, state) do
|
||||
packet = :pkt.decapsulate(data)
|
||||
packet_len = length(packet)
|
||||
send(state.tester_pid, {to_string(state.ifname), Enum.take(packet, packet_len - 1)})
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(_info, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
# private functions
|
||||
|
||||
defp init_pf(ifname, tester_pid) do
|
||||
{:ok, epcap_pid} = :epcap.start_link(interface: ifname, promiscuous: true, inject: true)
|
||||
%State{pcap_ref: epcap_pid, ifname: ifname, tester_pid: tester_pid}
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue