Implement Openflow Protocol and Callback system
This commit is contained in:
parent
fc02a678de
commit
e52fe31b79
48 changed files with 937 additions and 244 deletions
|
|
@ -1 +0,0 @@
|
|||
shun159@shun159.5674:1510580208
|
||||
|
|
@ -14,15 +14,12 @@ defmodule Openflow.Action.NxBundle do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
hash_field = Keyword.get(options, :hash_field, :eth_src)
|
||||
basis = Keyword.get(options, :basis, 0)
|
||||
alg = Keyword.get(options, :algorithm, :active_backup)
|
||||
slaves = Keyword.get(options, :slaves, [])
|
||||
%NxBundle{algorithm: alg,
|
||||
hash_field: hash_field,
|
||||
basis: basis,
|
||||
n_slaves: length(slaves),
|
||||
slaves: slaves}
|
||||
slaves = options[:slaves] || []
|
||||
%NxBundle{algorithm: options[:algorithm] || :active_backup,
|
||||
hash_field: options[:hash_field] || :eth_src,
|
||||
basis: options[:basis] || 0,
|
||||
n_slaves: length(slaves),
|
||||
slaves: slaves}
|
||||
end
|
||||
|
||||
def to_binary(%NxBundle{algorithm: alg,
|
||||
|
|
|
|||
|
|
@ -19,22 +19,17 @@ defmodule Openflow.Action.NxBundleLoad do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
hash_field = Keyword.get(options, :hash_field, :eth_src)
|
||||
basis = Keyword.get(options, :basis, 0)
|
||||
alg = Keyword.get(options, :algorithm, :active_backup)
|
||||
slaves = Keyword.get(options, :slaves, [])
|
||||
dst_field = Keyword.get(options, :dst_field)
|
||||
dst_field = options[:dst_field]
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(dst_field)
|
||||
n_bits = Keyword.get(options, :n_bits, default_n_bits)
|
||||
ofs = Keyword.get(options, :offset, 0)
|
||||
%NxBundleLoad{algorithm: alg,
|
||||
hash_field: hash_field,
|
||||
basis: basis,
|
||||
n_slaves: length(slaves),
|
||||
slaves: slaves,
|
||||
offset: ofs,
|
||||
n_bits: n_bits,
|
||||
dst_field: dst_field}
|
||||
slaves = options[:slaves] || []
|
||||
%NxBundleLoad{algorithm: options[:algorithm] || :active_backup,
|
||||
hash_field: options[:hash_field] || :eth_src,
|
||||
basis: options[:basis] || 0,
|
||||
n_slaves: length(slaves),
|
||||
slaves: slaves,
|
||||
offset: options[:offset] || 0,
|
||||
n_bits: options[:n_bits] || default_n_bits,
|
||||
dst_field: options[:dst_field]}
|
||||
end
|
||||
|
||||
def to_binary(%NxBundleLoad{algorithm: alg,
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ defmodule Openflow.Action.NxConjunction do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
clause = Keyword.get(options, :clause, 0)
|
||||
n_clauses = Keyword.get(options, :n_clauses, 0)
|
||||
id = Keyword.get(options, :id, 0)
|
||||
%NxConjunction{clause: clause, n_clauses: n_clauses, id: id}
|
||||
%NxConjunction{clause: options[:clause] || 0,
|
||||
n_clauses: options[:n_clauses] || 0,
|
||||
id: options[:id] || 0}
|
||||
end
|
||||
|
||||
def to_binary(%NxConjunction{clause: clause, n_clauses: n_clauses, id: id}) do
|
||||
|
|
|
|||
|
|
@ -18,24 +18,14 @@ defmodule Openflow.Action.NxConntrack do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options \\ []) do
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
zone_src = Keyword.get(options, :zone_src)
|
||||
zone_ofs = Keyword.get(options, :zone_offset)
|
||||
zone_n_bits = Keyword.get(options, :zone_n_bits)
|
||||
zone_imm = Keyword.get(options, :zone_imm, 0)
|
||||
recirc_table = Keyword.get(options, :recirc_table, 255)
|
||||
alg = Keyword.get(options, :alg, 0)
|
||||
exec = Keyword.get(options, :exec, [])
|
||||
%NxConntrack{
|
||||
flags: flags,
|
||||
zone_src: zone_src,
|
||||
zone_imm: zone_imm,
|
||||
zone_offset: zone_ofs,
|
||||
zone_n_bits: zone_n_bits,
|
||||
recirc_table: recirc_table,
|
||||
alg: alg,
|
||||
exec: exec
|
||||
}
|
||||
%NxConntrack{flags: options[:flags] || [],
|
||||
zone_src: options[:zone_src],
|
||||
zone_imm: options[:zone_imm] || 0,
|
||||
zone_offset: options[:zone_offset],
|
||||
zone_n_bits: options[:zone_n_bits],
|
||||
recirc_table: options[:recirc_table] || 255,
|
||||
alg: options[:alg] || 0,
|
||||
exec: options[:exec] || []}
|
||||
end
|
||||
|
||||
def to_binary(%NxConntrack{
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ defmodule Openflow.Action.NxController do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
max_len = Keyword.get(options, :max_len, :no_buffer)
|
||||
controller_id = Keyword.get(options, :id, 0)
|
||||
reason = Keyword.get(options, :reason, :action)
|
||||
%NxController{max_len: max_len, id: controller_id, reason: reason}
|
||||
%NxController{max_len: options[:max_len] || :no_buffer,
|
||||
id: options[:id] || 0,
|
||||
reason: options[:reason] || :action}
|
||||
end
|
||||
|
||||
def to_binary(%NxController{max_len: max_len, id: controller_id, reason: reason}) do
|
||||
|
|
|
|||
|
|
@ -21,16 +21,11 @@ defmodule Openflow.Action.NxController2 do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
max_len = Keyword.get(options, :max_len, :no_buffer)
|
||||
controller_id = Keyword.get(options, :id, 0)
|
||||
reason = Keyword.get(options, :reason, :action)
|
||||
userdata = Keyword.get(options, :userdata)
|
||||
pause = Keyword.get(options, :pause, false)
|
||||
%NxController2{max_len: max_len,
|
||||
id: controller_id,
|
||||
reason: reason,
|
||||
userdata: userdata,
|
||||
pause: pause}
|
||||
%NxController2{max_len: options[:max_len] || :no_buffer,
|
||||
id: options[:id] || 0,
|
||||
reason: options[:reason] || :action,
|
||||
userdata: options[:userdata],
|
||||
pause: options[:pause] || false}
|
||||
end
|
||||
|
||||
def to_binary(%NxController2{} = ctl) do
|
||||
|
|
|
|||
|
|
@ -10,9 +10,8 @@ defmodule Openflow.Action.NxFinTimeout do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
fin_idle = Keyword.get(options, :idle_timeout, 0)
|
||||
fin_hard = Keyword.get(options, :hard_timeout, 0)
|
||||
%NxFinTimeout{idle_timeout: fin_idle, hard_timeout: fin_hard}
|
||||
%NxFinTimeout{idle_timeout: options[:idle_timeout] || 0,
|
||||
hard_timeout: options[:hard_timeout] || 0}
|
||||
end
|
||||
|
||||
def to_binary(%NxFinTimeout{idle_timeout: fin_idle, hard_timeout: fin_hard}) do
|
||||
|
|
|
|||
|
|
@ -14,17 +14,13 @@ defmodule Openflow.Action.NxFlowSpecLoad do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src = Keyword.get(options, :src)
|
||||
dst = Keyword.get(options, :dst)
|
||||
src_ofs = Keyword.get(options, :src_offset, 0)
|
||||
dst_ofs = Keyword.get(options, :dst_offset, 0)
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(dst)
|
||||
n_bits = Keyword.get(options, :n_bits, default_n_bits)
|
||||
%NxFlowSpecLoad{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs}
|
||||
dst = options[:dst]
|
||||
n_bits = options[:n_bits] || Openflow.Match.Field.n_bits_of(dst)
|
||||
%NxFlowSpecLoad{src: options[:src],
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: options[:src_offset] || 0,
|
||||
dst_offset: options[:dst_offset] || 0}
|
||||
end
|
||||
|
||||
def to_binary(%NxFlowSpecLoad{} = fsm) do
|
||||
|
|
|
|||
|
|
@ -14,17 +14,13 @@ defmodule Openflow.Action.NxFlowSpecMatch do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src = Keyword.get(options, :src)
|
||||
dst = Keyword.get(options, :dst)
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(dst)
|
||||
n_bits = Keyword.get(options, :n_bits, default_n_bits)
|
||||
src_ofs = Keyword.get(options, :src_offset, 0)
|
||||
dst_ofs = Keyword.get(options, :dst_offset, 0)
|
||||
%NxFlowSpecMatch{src: src,
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: src_ofs,
|
||||
dst_offset: dst_ofs}
|
||||
dst = options[:dst]
|
||||
n_bits = options[:n_bits] || Openflow.Match.Field.n_bits_of(dst)
|
||||
%NxFlowSpecMatch{src: options[:src],
|
||||
dst: dst,
|
||||
n_bits: n_bits,
|
||||
src_offset: options[:src_offset] || 0,
|
||||
dst_offset: options[:dst_offset] || 0}
|
||||
end
|
||||
|
||||
def to_binary(%NxFlowSpecMatch{} = fsm) do
|
||||
|
|
|
|||
|
|
@ -11,13 +11,11 @@ defmodule Openflow.Action.NxFlowSpecOutput do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
src = Keyword.get(options, :src)
|
||||
src_ofs = Keyword.get(options, :src_offset, 0)
|
||||
default_n_bits = Openflow.Match.Field.n_bits_of(src)
|
||||
n_bits = Keyword.get(options, :n_bits, default_n_bits)
|
||||
%NxFlowSpecOutput{n_bits: n_bits,
|
||||
src: src,
|
||||
src_offset: src_ofs}
|
||||
src = options[:src]
|
||||
n_bits = options[:n_bits] || Openflow.Match.Field.n_bits_of(src)
|
||||
%NxFlowSpecOutput{n_bits: n_bits,
|
||||
src: src,
|
||||
src_offset: options[:src_offset] || 0}
|
||||
end
|
||||
|
||||
def to_binary(%NxFlowSpecOutput{n_bits: n_bits,
|
||||
|
|
|
|||
|
|
@ -17,24 +17,15 @@ defmodule Openflow.Action.NxLearn do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
idle = Keyword.get(options, :idle_timeout, 0)
|
||||
hard = Keyword.get(options, :hard_timeout, 0)
|
||||
prio = Keyword.get(options, :priority, 0)
|
||||
cookie = Keyword.get(options, :cookie, 0)
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
table_id = Keyword.get(options, :table_id, 0)
|
||||
fin_idle = Keyword.get(options, :fin_idle_timeout, 0)
|
||||
fin_hard = Keyword.get(options, :fin_hard_timeout, 0)
|
||||
flow_specs = Keyword.get(options, :flow_specs, [])
|
||||
%NxLearn{idle_timeout: idle,
|
||||
hard_timeout: hard,
|
||||
priority: prio,
|
||||
cookie: cookie,
|
||||
flags: flags,
|
||||
table_id: table_id,
|
||||
fin_idle_timeout: fin_idle,
|
||||
fin_hard_timeout: fin_hard,
|
||||
flow_specs: flow_specs}
|
||||
%NxLearn{idle_timeout: options[:idle_timeout] || 0,
|
||||
hard_timeout: options[:hard_timeout] || 0,
|
||||
priority: options[:priority] || 0,
|
||||
cookie: options[:cookie] || 0,
|
||||
flags: options[:flags] || [],
|
||||
table_id: options[:table_id] || 0xff,
|
||||
fin_idle_timeout: options[:fin_idle_timeout] || 0,
|
||||
fin_hard_timeout: options[:fin_hard_timeout] || 0,
|
||||
flow_specs: options[:flow_specs] || []}
|
||||
end
|
||||
|
||||
def to_binary(%NxLearn{idle_timeout: idle,
|
||||
|
|
@ -52,7 +43,7 @@ defmodule Openflow.Action.NxLearn do
|
|||
prio::16, cookie::64, flags_int::16, table_id::8,
|
||||
0::size(1)-unit(8), fin_idle::16, fin_hard::16,
|
||||
flow_specs_bin::bitstring>>
|
||||
exp_body_size = byte_size(exp_body)
|
||||
exp_body_size = byte_size(exp_body)
|
||||
padding_length = Openflow.Utils.padding(4 + exp_body_size, 8)
|
||||
length = 4 + exp_body_size + padding_length
|
||||
<<0xffff::16, length::16, exp_body::bytes, 0::size(padding_length)-unit(8)>>
|
||||
|
|
|
|||
|
|
@ -20,30 +20,18 @@ defmodule Openflow.Action.NxLearn2 do
|
|||
alias __MODULE__
|
||||
|
||||
def new(options) do
|
||||
idle = Keyword.get(options, :idle_timeout, 0)
|
||||
hard = Keyword.get(options, :hard_timeout, 0)
|
||||
prio = Keyword.get(options, :priority, 0)
|
||||
cookie = Keyword.get(options, :cookie, 0)
|
||||
flags = Keyword.get(options, :flags, [])
|
||||
table_id = Keyword.get(options, :table_id, 0)
|
||||
fin_idle = Keyword.get(options, :fin_idle_timeout, 0)
|
||||
fin_hard = Keyword.get(options, :fin_hard_timeout, 0)
|
||||
flow_specs = Keyword.get(options, :flow_specs, [])
|
||||
limit = Keyword.get(options, :limit, 0)
|
||||
result_dst_offset = Keyword.get(options, :result_dst_offset, 0)
|
||||
result_dst = Keyword.get(options, :result_dst)
|
||||
%NxLearn2{idle_timeout: idle,
|
||||
hard_timeout: hard,
|
||||
priority: prio,
|
||||
cookie: cookie,
|
||||
flags: flags,
|
||||
table_id: table_id,
|
||||
fin_idle_timeout: fin_idle,
|
||||
fin_hard_timeout: fin_hard,
|
||||
limit: limit,
|
||||
result_dst_offset: result_dst_offset,
|
||||
result_dst: result_dst,
|
||||
flow_specs: flow_specs}
|
||||
%NxLearn2{idle_timeout: options[:idle_timeout] || 0,
|
||||
hard_timeout: options[:hard_timeout] || 0,
|
||||
priority: options[:priority] || 0,
|
||||
cookie: options[:cookie] || 0,
|
||||
flags: options[:flags] || [],
|
||||
table_id: options[:table_id] || 0xff,
|
||||
fin_idle_timeout: options[:fin_idle_timeout] || 0,
|
||||
fin_hard_timeout: options[:fin_hard_timeout] || 0,
|
||||
limit: options[:limit] || 0,
|
||||
result_dst_offset: options[:result_dst_offset] || 0,
|
||||
result_dst: options[:result_dst],
|
||||
flow_specs: options[:flow_specs] || []}
|
||||
end
|
||||
|
||||
def to_binary(%NxLearn2{idle_timeout: idle,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ defmodule Openflow.Action.SetField do
|
|||
end
|
||||
|
||||
def read(<<25::16, _length::16, match_field_bin::bytes>>) do
|
||||
<<_class::16, _field::7, _hm::1, flen::8, _rest::bytes>>= match_field_bin
|
||||
<<_class::16, _field::7, _hm::1, flen::8, _rest::bytes>> = match_field_bin
|
||||
match_len = 4 + 4 + flen
|
||||
match_bin = <<1::16, match_len::16, match_field_bin::bytes>>
|
||||
{[field|_], _rest} = Openflow.Match.read(match_bin)
|
||||
|
|
|
|||
|
|
@ -316,8 +316,9 @@ defmodule Openflow.Enums do
|
|||
],
|
||||
|
||||
experimenter_oxm_vendors: [
|
||||
nicira_ext_match: 0x00002320,
|
||||
onf_ext_match: 0x4f4e4600
|
||||
nicira_ext_match: 0x00002320,
|
||||
hp_ext_match: 0x00002428,
|
||||
onf_ext_match: 0x4f4e4600
|
||||
],
|
||||
|
||||
match_type: [
|
||||
|
|
@ -618,6 +619,24 @@ defmodule Openflow.Enums do
|
|||
nsh_c4: 9
|
||||
],
|
||||
|
||||
hp_ext_match: [
|
||||
hp_udp_src_port_range: 0,
|
||||
hp_udp_dst_port_range: 1,
|
||||
hp_tcp_src_port_range: 2,
|
||||
hp_tcp_dst_port_range: 3,
|
||||
hp_tcp_flags: 4,
|
||||
hp_custom_1: 5,
|
||||
hp_custom_2: 6,
|
||||
hp_custom_3: 7,
|
||||
hp_custom_4: 8
|
||||
],
|
||||
|
||||
hp_custom_match_type: [
|
||||
l2_start: 1,
|
||||
l3_start: 2,
|
||||
l4_start: 3
|
||||
],
|
||||
|
||||
onf_ext_match: [
|
||||
onf_tcp_flags: 42,
|
||||
onf_actset_output: 43,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defmodule Openflow.Match do
|
|||
|
||||
def read(binary) do
|
||||
<<1::16, no_pad_len::16, binary1::binary>> = binary
|
||||
padding_length = @match_size - rem(no_pad_len, 8)
|
||||
padding_length = Openflow.Utils.pad_length(no_pad_len, 8)
|
||||
match_field_len = no_pad_len - @header_size
|
||||
<<match_fields::size(match_field_len)-binary, _::size(padding_length)-unit(8), rest::bitstring>> = binary1
|
||||
{decode_fields(match_fields, []), rest}
|
||||
|
|
@ -58,7 +58,7 @@ defmodule Openflow.Match do
|
|||
|
||||
def header_size(<<_oxm_class_int::16, _oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8, _::bytes>>),
|
||||
do: 4
|
||||
def header_size(<<0xffff::16, _oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8, _exp_int::32, _::bytes>>),
|
||||
def header_size(<<0xffff::16, _oxm_field_int::7, _oxm_has_mask::1, _oxm_length::8, _exp_int::32, _::bytes>>),
|
||||
do: 8
|
||||
|
||||
# private functions
|
||||
|
|
|
|||
|
|
@ -275,6 +275,17 @@ defmodule Openflow.Match.Field do
|
|||
def vendor_of(:nsh_c3), do: :nicira_ext_match
|
||||
def vendor_of(:nsh_c4), do: :nicira_ext_match
|
||||
|
||||
# HP Ext Match
|
||||
def vendor_of(:hp_udp_src_port_range), do: :hp_ext_match
|
||||
def vendor_of(:hp_udp_dst_port_range), do: :hp_ext_match
|
||||
def vendor_of(:hp_tcp_src_port_range), do: :hp_ext_match
|
||||
def vendor_of(:hp_tcp_dst_port_range), do: :hp_ext_match
|
||||
def vendor_of(:hp_tcp_flags), do: :hp_ext_match
|
||||
def vendor_of(:hp_custom_1), do: :hp_ext_match
|
||||
def vendor_of(:hp_custom_2), do: :hp_ext_match
|
||||
def vendor_of(:hp_custom_3), do: :hp_ext_match
|
||||
def vendor_of(:hp_custom_4), do: :hp_ext_match
|
||||
|
||||
# ONF Ext Match
|
||||
def vendor_of(:onf_tcp_flags), do: :onf_ext_match
|
||||
def vendor_of(:onf_actset_output), do: :onf_ext_match
|
||||
|
|
@ -518,6 +529,17 @@ defmodule Openflow.Match.Field do
|
|||
def format_of(:nsh_c3), do: {:be32, :decimal}
|
||||
def format_of(:nsh_c4), do: {:be32, :decimal}
|
||||
|
||||
# HP Ext Match
|
||||
def format_of(:hp_udp_src_port_range), do: {:be32, :decimal}
|
||||
def format_of(:hp_udp_dst_port_range), do: {:be32, :decimal}
|
||||
def format_of(:hp_tcp_src_port_range), do: {:be32, :decimal}
|
||||
def format_of(:hp_tcp_dst_port_range), do: {:be32, :decimal}
|
||||
def format_of(:hp_tcp_flags), do: {:be16, :tcp_flags}
|
||||
def format_of(:hp_custom_1), do: {:dynamic, :bytes}
|
||||
def format_of(:hp_custom_2), do: {:dynamic, :bytes}
|
||||
def format_of(:hp_custom_3), do: {:dynamic, :bytes}
|
||||
def format_of(:hp_custom_4), do: {:dynamic, :bytes}
|
||||
|
||||
# ONF Ext Match
|
||||
def format_of(:onf_tcp_flags), do: {:be16, :tcp_flags}
|
||||
def format_of(:onf_actset_output), do: {:be32, :openflow13_port}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Aggregate.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
packet_count: 0,
|
||||
byte_count: 0,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Desc.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
mfr_desc: "",
|
||||
hw_desc: "",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Flow.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
flows: []
|
||||
)
|
||||
|
|
@ -19,6 +20,16 @@ defmodule Openflow.Multipart.Flow.Reply do
|
|||
flows = Openflow.Multipart.FlowStats.read(flows_bin)
|
||||
%Reply{flows: flows}
|
||||
end
|
||||
|
||||
def append_body(%Reply{flows: flows} = message, %Reply{flags: [:more], flows: continue}) do
|
||||
%{message|flows: [continue|flows]}
|
||||
end
|
||||
def append_body(%Reply{flows: flows} = message, %Reply{flags: [], flows: continue}) do
|
||||
new_flows = [continue|flows]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|flows: new_flows}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.FlowStats do
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ defmodule Openflow.Multipart.Flow.Request do
|
|||
|
||||
def ofp_type, do: 18
|
||||
|
||||
def new(options) do
|
||||
def new(options \\ []) do
|
||||
table_id = Keyword.get(options, :table_id, :all)
|
||||
out_port = Keyword.get(options, :out_port, :any)
|
||||
out_group = Keyword.get(options, :out_group, :any)
|
||||
cookie = Keyword.get(options, :cookie, 0)
|
||||
cookie_mask = Keyword.get(options, :cookie, 0)
|
||||
match = Keyword.get(options, :match, [])
|
||||
match = Keyword.get(options, :match, Openflow.Match.new)
|
||||
%Request{table_id: table_id,
|
||||
out_port: out_port,
|
||||
out_group: out_group,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Group.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
groups: []
|
||||
)
|
||||
|
|
@ -19,6 +20,16 @@ defmodule Openflow.Multipart.Group.Reply do
|
|||
groups = Openflow.Multipart.Group.read(groups_bin)
|
||||
%Reply{groups: groups}
|
||||
end
|
||||
|
||||
def append_body(%Reply{groups: groups} = message, %Reply{flags: [:more], groups: continue}) do
|
||||
%{message|groups: [continue|groups]}
|
||||
end
|
||||
def append_body(%Reply{groups: groups} = message, %Reply{flags: [], groups: continue}) do
|
||||
new_groups = [continue|groups]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|groups: new_groups}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.Group do
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@ defmodule Openflow.Multipart.GroupDesc.Reply do
|
|||
groups = Openflow.Multipart.GroupDescStats.read(groups_bin)
|
||||
%Reply{groups: groups}
|
||||
end
|
||||
|
||||
def append_body(%Reply{groups: groups} = message, %Reply{flags: [:more], groups: continue}) do
|
||||
%{message|groups: [continue|groups]}
|
||||
end
|
||||
def append_body(%Reply{groups: groups} = message, %Reply{flags: [], groups: continue}) do
|
||||
new_groups = [continue|groups]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|groups: new_groups}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.GroupDescStats do
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.GroupFeatures.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
types: 0,
|
||||
capabilities: [],
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Meter.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
meters: []
|
||||
)
|
||||
|
|
@ -15,6 +16,16 @@ defmodule Openflow.Multipart.Meter.Reply do
|
|||
meters = Openflow.Multipart.Meter.read(meters_bin)
|
||||
%Reply{meters: meters}
|
||||
end
|
||||
|
||||
def append_body(%Reply{meters: meters} = message, %Reply{flags: [:more], meters: continue}) do
|
||||
%{message|meters: [continue|meters]}
|
||||
end
|
||||
def append_body(%Reply{meters: meters} = message, %Reply{flags: [], meters: continue}) do
|
||||
new_meters = [continue|meters]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|meters: new_meters}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.Meter do
|
||||
|
|
|
|||
33
lib/openflow/multipart/port_desc/reply.ex
Normal file
33
lib/openflow/multipart/port_desc/reply.ex
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
defmodule Openflow.Multipart.PortDesc.Reply do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
ports: []
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 18
|
||||
|
||||
def new(ports \\ []) do
|
||||
%Reply{ports: ports}
|
||||
end
|
||||
|
||||
def read(<<ports_bin::bytes>>) do
|
||||
ports = for (<<port_bin::64-bytes <- ports_bin>>), do: Openflow.Port.read(port_bin)
|
||||
%Reply{ports: Enum.reverse(ports)}
|
||||
end
|
||||
|
||||
def append_body(%Reply{ports: ports} = message, %Reply{flags: [:more], ports: continue}) do
|
||||
%{message|ports: [continue|ports]}
|
||||
end
|
||||
def append_body(%Reply{ports: ports} = message, %Reply{flags: [], ports: continue}) do
|
||||
new_ports = [continue|ports]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|ports: new_ports}
|
||||
end
|
||||
end
|
||||
24
lib/openflow/multipart/port_desc/request.ex
Normal file
24
lib/openflow/multipart/port_desc/request.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
defmodule Openflow.Multipart.PortDesc.Request do
|
||||
defstruct(
|
||||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
flags: []
|
||||
)
|
||||
|
||||
alias __MODULE__
|
||||
|
||||
def ofp_type, do: 18
|
||||
|
||||
def new do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def read("") do
|
||||
%Request{}
|
||||
end
|
||||
|
||||
def to_binary(%Request{} = msg) do
|
||||
Openflow.Multipart.Request.header(msg)
|
||||
end
|
||||
end
|
||||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.PortStats.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
ports: []
|
||||
)
|
||||
|
|
@ -19,6 +20,16 @@ defmodule Openflow.Multipart.PortStats.Reply do
|
|||
ports = Openflow.Multipart.PortStats.read(ports_bin)
|
||||
%Reply{ports: ports}
|
||||
end
|
||||
|
||||
def append_body(%Reply{ports: ports} = message, %Reply{flags: [:more], ports: continue}) do
|
||||
%{message|ports: [continue|ports]}
|
||||
end
|
||||
def append_body(%Reply{ports: ports} = message, %Reply{flags: [], ports: continue}) do
|
||||
new_ports = [continue|ports]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|ports: new_ports}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.PortStats do
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Queue.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
queues: []
|
||||
)
|
||||
|
|
@ -19,6 +20,16 @@ defmodule Openflow.Multipart.Queue.Reply do
|
|||
queues = Openflow.Multipart.Queue.read(queues_bin)
|
||||
%Reply{queues: queues}
|
||||
end
|
||||
|
||||
def append_body(%Reply{queues: queues} = message, %Reply{flags: [:more], queues: continue}) do
|
||||
%{message|queues: [continue|queues]}
|
||||
end
|
||||
def append_body(%Reply{queues: queues} = message, %Reply{flags: [], queues: continue}) do
|
||||
new_queues = [continue|queues]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|queues: new_queues}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.Queue do
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ defmodule Openflow.Multipart.Table.Reply do
|
|||
version: 4,
|
||||
xid: 0,
|
||||
datapath_id: nil, # virtual field
|
||||
aux_id: nil,
|
||||
flags: [],
|
||||
tables: []
|
||||
)
|
||||
|
|
@ -15,6 +16,16 @@ defmodule Openflow.Multipart.Table.Reply do
|
|||
tables = Openflow.Multipart.TableStats.read(tables_bin)
|
||||
%Reply{tables: tables}
|
||||
end
|
||||
|
||||
def append_body(%Reply{tables: tables} = message, %Reply{flags: [:more], tables: continue}) do
|
||||
%{message|tables: [continue|tables]}
|
||||
end
|
||||
def append_body(%Reply{tables: tables} = message, %Reply{flags: [], tables: continue}) do
|
||||
new_tables = [continue|tables]
|
||||
|> Enum.reverse
|
||||
|> List.flatten
|
||||
%{message|tables: new_tables}
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Openflow.Multipart.TableStats do
|
||||
|
|
|
|||
|
|
@ -13,14 +13,13 @@ defmodule Openflow.NxPacketIn2 do
|
|||
reason: nil,
|
||||
metadata: nil,
|
||||
userdata: nil,
|
||||
continuation: nil,
|
||||
# continuation properties:
|
||||
continuation_bridge: nil,
|
||||
continuation_stack: nil,
|
||||
continuation_conntracked: nil,
|
||||
continuation_bridge: "",
|
||||
continuation_stack: [],
|
||||
continuation_conntracked: false,
|
||||
continuation_table_id: nil,
|
||||
continuation_cookie: nil,
|
||||
continuation_actions: nil,
|
||||
continuation_actions: [],
|
||||
continuation_action_set: nil
|
||||
)
|
||||
|
||||
|
|
@ -29,6 +28,138 @@ defmodule Openflow.NxPacketIn2 do
|
|||
@experimenter 0x00002320
|
||||
@nx_type 30
|
||||
|
||||
@packet 0
|
||||
@full_len 1
|
||||
@buffer_id 2
|
||||
@table_id 3
|
||||
@cookie 4
|
||||
@reason 5
|
||||
@metadata 6
|
||||
@userdata 7
|
||||
@continuation 8
|
||||
|
||||
@nxcpt_bridge 0x8000
|
||||
@nxcpt_stack 0x8001
|
||||
@nxcpt_mirrors 0x8002
|
||||
@nxcpt_conntracked 0x8003
|
||||
@nxcpt_table_id 0x8004
|
||||
@nxcpt_cookie 0x8005
|
||||
@nxcpt_actions 0x8006
|
||||
@nxcpt_action_set 0x8007
|
||||
|
||||
@prop_header_length 4
|
||||
|
||||
def ofp_type, do: 4
|
||||
|
||||
def read(<<@experimenter::32, @nx_type::32, props_bin::bytes>>) do
|
||||
%NxPacketIn2{}
|
||||
|> decode_props(props_bin)
|
||||
end
|
||||
|
||||
## private functions
|
||||
|
||||
defp decode_props(pktin, ""), do: pktin
|
||||
defp decode_props(pktin, <<@packet::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
packet_length = length - @prop_header_length
|
||||
<<packet::size(packet_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_props(%{pktin|packet: packet}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@full_len::16, _length::16, full_len::32, rest::bytes>>) do
|
||||
decode_props(%{pktin|full_len: full_len}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@buffer_id::16, _length::16, buffer_id::32, rest::bytes>>) do
|
||||
decode_props(%{pktin|buffer_id: buffer_id}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@table_id::16, _length::16, table_id::8, _::24, rest::bytes>>) do
|
||||
decode_props(%{pktin|table_id: table_id}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@cookie::16, _length::16, _::32, cookie::64, rest::bytes>>) do
|
||||
decode_props(%{pktin|cookie: cookie}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@reason::16, _length::16, reason_int::8, _::24, rest::bytes>>) do
|
||||
reason = Openflow.Enums.to_atom(reason_int, :packet_in_reason)
|
||||
decode_props(%{pktin|reason: reason}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@metadata::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
match_field_length = length - @prop_header_length
|
||||
<<match_fields_bin::size(match_field_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
match_len = 4 + byte_size(match_fields_bin)
|
||||
padding = Openflow.Utils.pad_length(match_len, 8)
|
||||
match_bin = (<<1::16, match_len::16, match_fields_bin::bytes, 0::size(padding)-unit(8)>>)
|
||||
{fields, _rest} = Openflow.Match.read(match_bin)
|
||||
decode_props(%{pktin|metadata: fields}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@userdata::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
userdata_length = length - @prop_header_length
|
||||
<<userdata::size(userdata_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_props(%{pktin|userdata: userdata}, rest)
|
||||
end
|
||||
defp decode_props(pktin, <<@continuation::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length - 4
|
||||
<<_pad::32, data::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
pktin
|
||||
|> decode_continuations(data)
|
||||
|> decode_props(rest)
|
||||
end
|
||||
defp decode_props(pktin, <<_::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length
|
||||
<<_data::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_props(pktin, rest)
|
||||
end
|
||||
|
||||
defp decode_continuations(pktin, ""), do: pktin
|
||||
defp decode_continuations(pktin, <<@nxcpt_bridge::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length
|
||||
<<bridge::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_bridge: bridge}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_stack::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = (length - @prop_header_length) * 8
|
||||
<<stack::size(data_length), _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_stack: pktin.continuation_stack ++ [stack]}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_mirrors::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length
|
||||
<<mirrors::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_mirrors: mirrors}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_conntracked::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length
|
||||
<<_::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_conntracked: true}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_table_id::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
<<table_id::8, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_table_id: table_id}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_cookie::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
<<cookie::64, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_cookie: cookie}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_actions::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length - 4
|
||||
<<_pad::32, actions::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_actions: Openflow.Action.read(actions)}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, <<@nxcpt_action_set::16, length::16, tail::bytes>>) do
|
||||
pad_length = Openflow.Utils.pad_length(length, 8)
|
||||
data_length = length - @prop_header_length
|
||||
<<action_set::size(data_length)-bytes, _::size(pad_length)-unit(8), rest::bytes>> = tail
|
||||
decode_continuations(%{pktin|continuation_action_set: action_set}, rest)
|
||||
end
|
||||
defp decode_continuations(pktin, _) do
|
||||
decode_continuations(pktin, "")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue