Fix to handler start_link fail

This commit is contained in:
Eishun Kondoh 2018-02-02 01:55:46 +09:00
parent 0df6336f5e
commit 658b7448da
17 changed files with 17 additions and 2012 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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