Goto confession
This commit is contained in:
parent
7b1f581642
commit
ecfd278f2a
5 changed files with 239 additions and 47 deletions
17
test/flay.ex
17
test/flay.ex
|
|
@ -21,6 +21,7 @@ defmodule Flay do
|
|||
def init(args) do
|
||||
state = init_controller(args)
|
||||
init_bridge(state.datapath_id)
|
||||
GenServer.cast(Flay, :desc_stats)
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
|
|
@ -28,15 +29,15 @@ defmodule Flay do
|
|||
send_message(PortDesc.Request.new, state.datapath_id)
|
||||
{:noreply, %{state|reply_to: from}}
|
||||
end
|
||||
def handle_call(:desc_stats, from, state) do
|
||||
send_message(Desc.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
|
||||
|
|
@ -49,10 +50,6 @@ defmodule Flay do
|
|||
send_flow_mod_delete(state.datapath_id, match: Match.new)
|
||||
{:noreply, state}
|
||||
end
|
||||
def handle_cast(:restore_flow_profile, state) do
|
||||
send_message(state.default_profile, state.datapath_id)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(%ErrorMsg{} = error, state) do
|
||||
send(state.tester_pid, error)
|
||||
|
|
@ -70,8 +67,8 @@ defmodule Flay do
|
|||
{:noreply, %{state|reply_to: nil}}
|
||||
end
|
||||
def handle_info(%Desc.Reply{} = desc, state) do
|
||||
GenServer.reply(state.reply_to, desc)
|
||||
{:noreply, %{state|reply_to: nil}}
|
||||
IO.inspect(desc)
|
||||
{:noreply, state}
|
||||
end
|
||||
def handle_info(%Flow.Reply{} = desc, state) do
|
||||
GenServer.reply(state.reply_to, desc)
|
||||
|
|
|
|||
|
|
@ -2,18 +2,27 @@ defmodule FlogTest do
|
|||
use ExUnit.Case, async: false
|
||||
use Bitwise
|
||||
|
||||
@vlan_trunk_port "1" # FIXME:
|
||||
@access_port "2" # FIXME:
|
||||
@vxlan_port "5" # FIXME:
|
||||
@listen_port 6653
|
||||
|
||||
@vlan_trunk_port "veth0" # FIXME:
|
||||
@access_port "veth3" # FIXME:
|
||||
@vxlan_port "veth4" # FIXME:
|
||||
|
||||
@vlan_trunk_port_sniffer "veth1" # FIXME:
|
||||
@access_port_sniffer "veth2" # FIXME:
|
||||
@vxlan_port_sniffer "veth5" # FIXME:
|
||||
|
||||
@bootnet_vid 0x1000 ||| 5
|
||||
@user_vid 0x1000 ||| 123
|
||||
@vlan_present {0x1000, 0x1000}
|
||||
@mcast {"010000000000", "010000000000"}
|
||||
@sdl_vmac "000000000001"
|
||||
@bcast "ffffffffffff"
|
||||
@mac "010203040506"
|
||||
@mac "000102030405"
|
||||
@auth_ipv4_address {192,168,5,4}
|
||||
@captive_ipv4_address {192,168,5,5}
|
||||
@quad_0_ip {0,0,0,0}
|
||||
@bcast_ip {255,255,255,255}
|
||||
@client_ip {192,168,5,10}
|
||||
@client_farm_ip {192,168,255,1}
|
||||
@gateway_ip {192,168,5,4}
|
||||
|
|
@ -51,10 +60,6 @@ defmodule FlogTest do
|
|||
cookie: cookie,
|
||||
timeout: timeout
|
||||
]
|
||||
|
||||
on_exit fn ->
|
||||
GenServer.cast(Flay, :restore_flow_profile)
|
||||
end
|
||||
{:ok, options}
|
||||
end
|
||||
|
||||
|
|
@ -68,6 +73,26 @@ defmodule FlogTest do
|
|||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
end
|
||||
|
||||
test "Inject Packet(ARP)" do
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@mac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
payload = <<0::size(16)-unit(8)>>
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x0806),
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip)
|
||||
]
|
||||
Pf.inject!(pid1, packet, payload)
|
||||
refute_receive {@vlan_trunk_port_sniffer, [^packet, ^payload]}, 1000
|
||||
refute_receive {@vxlan_port_sniffer, [^packet, ^payload]}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
describe("switch:merged_handler:" <>
|
||||
|
|
@ -77,7 +102,7 @@ defmodule FlogTest do
|
|||
match = Openflow.Match.new(
|
||||
in_port: state.vlan_trunk.number,
|
||||
eth_dst: @bcast,
|
||||
vlan_vid: {0x0000, 0x1fff},
|
||||
vlan_vid: 0x0000,
|
||||
eth_type: 0x88cc
|
||||
)
|
||||
action = Openflow.Action.Output.new(:controller)
|
||||
|
|
@ -90,6 +115,28 @@ defmodule FlogTest do
|
|||
instructions: [ins]]
|
||||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(state.vlan_trunk.hw_addr, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x88cc),
|
||||
lldp(pdus: [chassis_id(value: "hogehoge"),
|
||||
port_id(subtype: :mac_address, value: shost),
|
||||
ttl(value: 128)])
|
||||
]
|
||||
Pf.inject!(pid2, packet)
|
||||
in_port = state.vlan_trunk.number
|
||||
assert_receive %Openflow.PacketIn{in_port: ^in_port}, 3000
|
||||
refute_receive {@vlan_trunk_port_sniffer, [^packet, ""]}, 1000
|
||||
refute_receive {@vxlan_port_sniffer, [^packet, ""]}, 1000
|
||||
refute_receive {@access_port_sniffer, [^packet, ""]}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -111,7 +158,7 @@ defmodule FlogTest do
|
|||
|
||||
describe("switch:uplink_escalation_flow:" <>
|
||||
"table=0,priority=10,cookie=0x2000000000000000,arp,actions=controller") do
|
||||
test "Install Flow" do
|
||||
test "Install Flow", state do
|
||||
match = Openflow.Match.new(eth_type: 0x0806)
|
||||
action = Openflow.Action.Output.new(:controller)
|
||||
ins = Openflow.Instruction.ApplyActions.new(action)
|
||||
|
|
@ -123,14 +170,34 @@ defmodule FlogTest do
|
|||
instructions: [ins]]
|
||||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@mac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
payload = <<0::size(16)-unit(8)>>
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x0806),
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip)
|
||||
]
|
||||
Pf.inject!(pid1, packet, payload)
|
||||
in_port = state.port.number
|
||||
assert_receive %Openflow.PacketIn{in_port: ^in_port}, 3000
|
||||
refute_receive {@vlan_trunk_port_sniffer, [^packet, ^payload]}, 1000
|
||||
refute_receive {@vxlan_port_sniffer, [^packet, ^payload]}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
describe("switch:uplink_escalation_flow:" <>
|
||||
"table=0,priority=10,cookie=0x2000000000000000,udp,udp_dst=67,actions=controller") do
|
||||
test "Install Flow" do
|
||||
test "Install Flow", state do
|
||||
match = Openflow.Match.new(eth_type: 0x0800, ip_proto: 17, udp_dst: 67)
|
||||
action = Openflow.Action.Output.new(:controller)
|
||||
action = Openflow.Action.Output.new(:controller)
|
||||
ins = Openflow.Instruction.ApplyActions.new(action)
|
||||
options =
|
||||
[cookie: 0x2000000000000000,
|
||||
|
|
@ -140,6 +207,32 @@ defmodule FlogTest do
|
|||
instructions: [ins]]
|
||||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@mac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
|
||||
payload = File.read!("test/packet_data/dhcp_discover.raw")
|
||||
length = 8 + byte_size(payload)
|
||||
udp_header = udp(sport: 68, dport: 67, ulen: length)
|
||||
ipv4_header = ipv4(saddr: @quad_0_ip, daddr: @bcast_ip, p: 17, len: 20 + length)
|
||||
udp_sum = :pkt.makesum([ipv4_header, udp_header, payload])
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x0800),
|
||||
ipv4_header,
|
||||
udp(udp_header, sum: udp_sum)
|
||||
]
|
||||
Pf.inject!(pid1, packet, <<payload::bytes>>)
|
||||
in_port = state.port.number
|
||||
assert_receive %Openflow.PacketIn{in_port: ^in_port}, 3000
|
||||
refute_receive {@vlan_trunk_port_sniffer, [^packet, ^payload]}, 1000
|
||||
refute_receive {@vxlan_port_sniffer, [^packet, ^payload]}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -155,6 +248,26 @@ defmodule FlogTest do
|
|||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
end
|
||||
|
||||
test "Inject Packet(ARP)" do
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@mac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
payload = <<0::size(16)-unit(8)>>
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x0806),
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip)
|
||||
]
|
||||
Pf.inject!(pid2, packet, payload)
|
||||
refute_receive {@access_port_sniffer, [^packet, ^payload]}, 1000
|
||||
refute_receive {@vxlan_port_sniffer, [^packet, ^payload]}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
describe("associate:register_bootstrap_rule:" <>
|
||||
|
|
@ -184,6 +297,28 @@ defmodule FlogTest do
|
|||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
end
|
||||
|
||||
test "Inject Packet(ARP)" do
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@mac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
packet = [ether(dhost: dhost, shost: shost, type: 0x0806),
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip)]
|
||||
expect = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x8100),
|
||||
{:"802.1q", 0, 0, 5, 0x0806},
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip),
|
||||
""
|
||||
]
|
||||
Pf.inject!(pid1, packet)
|
||||
assert_receive {@vlan_trunk_port_sniffer, ^expect}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
describe("associate:register_bootstrap_rule:" <>
|
||||
|
|
@ -213,6 +348,30 @@ defmodule FlogTest do
|
|||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
end
|
||||
|
||||
test "Inject Packet(ARP)" do
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@mac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@bcast, :eth_dst)
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x8100),
|
||||
{:"802.1q", 0, 0, 5, 0x0806},
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip),
|
||||
]
|
||||
expect = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x0806),
|
||||
arp(op: 1, sha: shost, sip: @client_ip, tip: @gateway_ip),
|
||||
""
|
||||
]
|
||||
Pf.inject!(pid2, packet)
|
||||
assert_receive {@access_port_sniffer, ^expect}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
describe("associate:register_bootstrap_rule:" <>
|
||||
|
|
@ -242,6 +401,30 @@ defmodule FlogTest do
|
|||
:ok = GenServer.cast(Flay, {:flow_install, options, self()})
|
||||
refute_receive %Openflow.ErrorMsg{}, 1000
|
||||
end
|
||||
|
||||
test "Inject Packet(ARP)" do
|
||||
{:ok, pid1} = Pf.start_link(@access_port_sniffer)
|
||||
{:ok, pid2} = Pf.start_link(@vlan_trunk_port_sniffer)
|
||||
{:ok, pid3} = Pf.start_link(@vxlan_port_sniffer)
|
||||
|
||||
shost = Openflow.Match.Field.codec(@sdl_vmac, :eth_src)
|
||||
dhost = Openflow.Match.Field.codec(@mac, :eth_dst)
|
||||
packet = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x8100),
|
||||
{:"802.1q", 0, 0, 5, 0x0806},
|
||||
arp(op: 1, sha: shost, tip: @client_ip, sip: @gateway_ip),
|
||||
]
|
||||
expect = [
|
||||
ether(dhost: dhost, shost: shost, type: 0x0806),
|
||||
arp(op: 1, sha: shost, tip: @client_ip, sip: @gateway_ip),
|
||||
""
|
||||
]
|
||||
Pf.inject!(pid2, packet)
|
||||
assert_receive {@access_port_sniffer, ^expect}, 1000
|
||||
Pf.stop(pid1)
|
||||
Pf.stop(pid2)
|
||||
Pf.stop(pid3)
|
||||
end
|
||||
end
|
||||
|
||||
describe("associate:register_bootstrap_rule:" <>
|
||||
|
|
@ -615,7 +798,7 @@ defmodule FlogTest do
|
|||
|
||||
defp setup_applications do
|
||||
Application.put_env(:tres, :protocol, :tcp, persistent: true)
|
||||
Application.put_env(:tres, :port, 6633, persistent: true)
|
||||
Application.put_env(:tres, :port, @listen_port, persistent: true)
|
||||
Application.put_env(:tres, :mac_connections, 1, persistent: true)
|
||||
Application.put_env(:tres, :mac_acceptors, 1, persistent: true)
|
||||
Application.put_env(:tres, :callback_module, Flay, persistent: true)
|
||||
|
|
@ -641,11 +824,4 @@ defmodule FlogTest do
|
|||
port_desc = GenServer.call(Flay, :port_desc_stats, 5000)
|
||||
port_desc.ports
|
||||
end
|
||||
|
||||
defp print_flows do
|
||||
flow_stats = GenServer.call(Flay, :flow_stats, 5000)
|
||||
for flow <- flow_stats.flows do
|
||||
IO.inspect(flow)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
BIN
test/packet_data/dhcp_discover.raw
Normal file
BIN
test/packet_data/dhcp_discover.raw
Normal file
Binary file not shown.
52
test/pf.ex
52
test/pf.ex
|
|
@ -1,6 +1,12 @@
|
|||
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,
|
||||
|
|
@ -9,8 +15,12 @@ defmodule Pf do
|
|||
]
|
||||
end
|
||||
|
||||
def inject!(pid, packet) do
|
||||
GenServer.cast(pid, {:inject, packet})
|
||||
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
|
||||
|
|
@ -19,22 +29,23 @@ defmodule Pf do
|
|||
end
|
||||
|
||||
def init([ifname, tester_pid]) do
|
||||
{:ok, epcap_pid} =
|
||||
:epcap.start_link(
|
||||
interface: ifname,
|
||||
promiscuous: true,
|
||||
inject: true
|
||||
)
|
||||
state = %State{
|
||||
pcap_ref: epcap_pid,
|
||||
ifname: ifname,
|
||||
tester_pid: tester_pid
|
||||
}
|
||||
{:ok, state}
|
||||
{:ok, init_pf(ifname, tester_pid)}
|
||||
end
|
||||
|
||||
def handle_cast({:inject, packet}, state) do
|
||||
:epcap.send(state.pcap_ref, packet)
|
||||
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
|
||||
|
|
@ -46,10 +57,17 @@ defmodule Pf do
|
|||
|
||||
def handle_info({:packet, _dlt, _time, _len, data}, state) do
|
||||
pkt = :pkt.decapsulate(data)
|
||||
send(state.tester_pid, {pkt, self()})
|
||||
send(state.tester_pid, {to_string(state.ifname), pkt})
|
||||
{: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
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
ExUnit.configure(seed: 0)
|
||||
ExUnit.start(trace: true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue