quality: Add test cases for group_desc and group_features messages

This commit is contained in:
Eishun Kondoh 2019-05-05 22:56:16 +09:00
parent 87ff193b63
commit b5d0a5654a
9 changed files with 1073 additions and 463 deletions

View file

@ -1,5 +1,5 @@
[ [
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"], inputs: ["mix.exs", "{config,lib,test,priv}/**/*.{ex,exs}"],
locals_without_parens: [ locals_without_parens: [
# Formatter tests # Formatter tests

View file

@ -3879,6 +3879,34 @@ defmodule Openflow.Enums do
throw(:bad_enum) throw(:bad_enum)
end end
def to_int(:all, :group_type_flags) do
group_type_flags_to_int(:all)
catch
_class, _reason -> :all
end
def to_int(:select, :group_type_flags) do
group_type_flags_to_int(:select)
catch
_class, _reason -> :select
end
def to_int(:indirect, :group_type_flags) do
group_type_flags_to_int(:indirect)
catch
_class, _reason -> :indirect
end
def to_int(:fast_failover, :group_type_flags) do
group_type_flags_to_int(:fast_failover)
catch
_class, _reason -> :fast_failover
end
def to_int(_int, :group_type_flags) do
throw(:bad_enum)
end
def to_int(:max, :group_id) do def to_int(:max, :group_id) do
group_id_to_int(:max) group_id_to_int(:max)
catch catch
@ -4225,6 +4253,136 @@ defmodule Openflow.Enums do
throw(:bad_enum) throw(:bad_enum)
end end
def to_int(Openflow.Action.Output, :action_flags) do
action_flags_to_int(Openflow.Action.Output)
catch
_class, _reason -> Openflow.Action.Output
end
def to_int(Openflow.Action.CopyTtlOut, :action_flags) do
action_flags_to_int(Openflow.Action.CopyTtlOut)
catch
_class, _reason -> Openflow.Action.CopyTtlOut
end
def to_int(Openflow.Action.CopyTtlIn, :action_flags) do
action_flags_to_int(Openflow.Action.CopyTtlIn)
catch
_class, _reason -> Openflow.Action.CopyTtlIn
end
def to_int(Openflow.Action.SetMplsTtl, :action_flags) do
action_flags_to_int(Openflow.Action.SetMplsTtl)
catch
_class, _reason -> Openflow.Action.SetMplsTtl
end
def to_int(Openflow.Action.DecMplsTtl, :action_flags) do
action_flags_to_int(Openflow.Action.DecMplsTtl)
catch
_class, _reason -> Openflow.Action.DecMplsTtl
end
def to_int(Openflow.Action.PushVlan, :action_flags) do
action_flags_to_int(Openflow.Action.PushVlan)
catch
_class, _reason -> Openflow.Action.PushVlan
end
def to_int(Openflow.Action.PopVlan, :action_flags) do
action_flags_to_int(Openflow.Action.PopVlan)
catch
_class, _reason -> Openflow.Action.PopVlan
end
def to_int(Openflow.Action.PushMpls, :action_flags) do
action_flags_to_int(Openflow.Action.PushMpls)
catch
_class, _reason -> Openflow.Action.PushMpls
end
def to_int(Openflow.Action.PopMpls, :action_flags) do
action_flags_to_int(Openflow.Action.PopMpls)
catch
_class, _reason -> Openflow.Action.PopMpls
end
def to_int(Openflow.Action.SetQueue, :action_flags) do
action_flags_to_int(Openflow.Action.SetQueue)
catch
_class, _reason -> Openflow.Action.SetQueue
end
def to_int(Openflow.Action.Group, :action_flags) do
action_flags_to_int(Openflow.Action.Group)
catch
_class, _reason -> Openflow.Action.Group
end
def to_int(Openflow.Action.SetNwTtl, :action_flags) do
action_flags_to_int(Openflow.Action.SetNwTtl)
catch
_class, _reason -> Openflow.Action.SetNwTtl
end
def to_int(Openflow.Action.DecNwTtl, :action_flags) do
action_flags_to_int(Openflow.Action.DecNwTtl)
catch
_class, _reason -> Openflow.Action.DecNwTtl
end
def to_int(Openflow.Action.SetField, :action_flags) do
action_flags_to_int(Openflow.Action.SetField)
catch
_class, _reason -> Openflow.Action.SetField
end
def to_int(Openflow.Action.PushPbb, :action_flags) do
action_flags_to_int(Openflow.Action.PushPbb)
catch
_class, _reason -> Openflow.Action.PushPbb
end
def to_int(Openflow.Action.PopPbb, :action_flags) do
action_flags_to_int(Openflow.Action.PopPbb)
catch
_class, _reason -> Openflow.Action.PopPbb
end
def to_int(Openflow.Action.Encap, :action_flags) do
action_flags_to_int(Openflow.Action.Encap)
catch
_class, _reason -> Openflow.Action.Encap
end
def to_int(Openflow.Action.Decap, :action_flags) do
action_flags_to_int(Openflow.Action.Decap)
catch
_class, _reason -> Openflow.Action.Decap
end
def to_int(Openflow.Action.SetSequence, :action_flags) do
action_flags_to_int(Openflow.Action.SetSequence)
catch
_class, _reason -> Openflow.Action.SetSequence
end
def to_int(Openflow.Action.ValidateSequence, :action_flags) do
action_flags_to_int(Openflow.Action.ValidateSequence)
catch
_class, _reason -> Openflow.Action.ValidateSequence
end
def to_int(Openflow.Action.Experimenter, :action_flags) do
action_flags_to_int(Openflow.Action.Experimenter)
catch
_class, _reason -> Openflow.Action.Experimenter
end
def to_int(_int, :action_flags) do
throw(:bad_enum)
end
def to_int(:nicira_ext_action, :action_vendor) do def to_int(:nicira_ext_action, :action_vendor) do
action_vendor_to_int(:nicira_ext_action) action_vendor_to_int(:nicira_ext_action)
catch catch
@ -9137,6 +9295,34 @@ defmodule Openflow.Enums do
throw(:bad_enum) throw(:bad_enum)
end end
def to_atom(0x1, :group_type_flags) do
group_type_flags_to_atom(0x1)
catch
_class, _reason -> 1
end
def to_atom(0x2, :group_type_flags) do
group_type_flags_to_atom(0x2)
catch
_class, _reason -> 2
end
def to_atom(0x4, :group_type_flags) do
group_type_flags_to_atom(0x4)
catch
_class, _reason -> 4
end
def to_atom(0x8, :group_type_flags) do
group_type_flags_to_atom(0x8)
catch
_class, _reason -> 8
end
def to_atom(_, :group_type_flags) do
throw(:bad_enum)
end
def to_atom(0xFFFFFF00, :group_id) do def to_atom(0xFFFFFF00, :group_id) do
group_id_to_atom(0xFFFFFF00) group_id_to_atom(0xFFFFFF00)
catch catch
@ -9483,6 +9669,136 @@ defmodule Openflow.Enums do
throw(:bad_enum) throw(:bad_enum)
end end
def to_atom(0x1, :action_flags) do
action_flags_to_atom(0x1)
catch
_class, _reason -> 1
end
def to_atom(0x800, :action_flags) do
action_flags_to_atom(0x800)
catch
_class, _reason -> 2048
end
def to_atom(0x1000, :action_flags) do
action_flags_to_atom(0x1000)
catch
_class, _reason -> 4096
end
def to_atom(0x8000, :action_flags) do
action_flags_to_atom(0x8000)
catch
_class, _reason -> 32768
end
def to_atom(0x10000, :action_flags) do
action_flags_to_atom(0x10000)
catch
_class, _reason -> 65536
end
def to_atom(0x20000, :action_flags) do
action_flags_to_atom(0x20000)
catch
_class, _reason -> 131_072
end
def to_atom(0x40000, :action_flags) do
action_flags_to_atom(0x40000)
catch
_class, _reason -> 262_144
end
def to_atom(0x80000, :action_flags) do
action_flags_to_atom(0x80000)
catch
_class, _reason -> 524_288
end
def to_atom(0x100000, :action_flags) do
action_flags_to_atom(0x100000)
catch
_class, _reason -> 1_048_576
end
def to_atom(0x200000, :action_flags) do
action_flags_to_atom(0x200000)
catch
_class, _reason -> 2_097_152
end
def to_atom(0x400000, :action_flags) do
action_flags_to_atom(0x400000)
catch
_class, _reason -> 4_194_304
end
def to_atom(0x800000, :action_flags) do
action_flags_to_atom(0x800000)
catch
_class, _reason -> 8_388_608
end
def to_atom(0x1000000, :action_flags) do
action_flags_to_atom(0x1000000)
catch
_class, _reason -> 16_777_216
end
def to_atom(0x2000000, :action_flags) do
action_flags_to_atom(0x2000000)
catch
_class, _reason -> 33_554_432
end
def to_atom(0x4000000, :action_flags) do
action_flags_to_atom(0x4000000)
catch
_class, _reason -> 67_108_864
end
def to_atom(0x8000000, :action_flags) do
action_flags_to_atom(0x8000000)
catch
_class, _reason -> 134_217_728
end
def to_atom(0x10000000, :action_flags) do
action_flags_to_atom(0x10000000)
catch
_class, _reason -> 268_435_456
end
def to_atom(0x20000000, :action_flags) do
action_flags_to_atom(0x20000000)
catch
_class, _reason -> 536_870_912
end
def to_atom(0x40000000, :action_flags) do
action_flags_to_atom(0x40000000)
catch
_class, _reason -> 1_073_741_824
end
def to_atom(0x80000000, :action_flags) do
action_flags_to_atom(0x80000000)
catch
_class, _reason -> 2_147_483_648
end
def to_atom(0xFFFF, :action_flags) do
action_flags_to_atom(0xFFFF)
catch
_class, _reason -> 65535
end
def to_atom(_, :action_flags) do
throw(:bad_enum)
end
def to_atom(0x2320, :action_vendor) do def to_atom(0x2320, :action_vendor) do
action_vendor_to_atom(0x2320) action_vendor_to_atom(0x2320)
catch catch
@ -11849,6 +12165,16 @@ defmodule Openflow.Enums do
def group_type_to_atom(0x2), do: :indirect def group_type_to_atom(0x2), do: :indirect
def group_type_to_atom(0x3), do: :fast_failover def group_type_to_atom(0x3), do: :fast_failover
def group_type_to_atom(_), do: throw(:bad_enum) def group_type_to_atom(_), do: throw(:bad_enum)
def group_type_flags_to_int(:all), do: 0x1
def group_type_flags_to_int(:select), do: 0x2
def group_type_flags_to_int(:indirect), do: 0x4
def group_type_flags_to_int(:fast_failover), do: 0x8
def group_type_flags_to_int(_), do: throw(:bad_enum)
def group_type_flags_to_atom(0x1), do: :all
def group_type_flags_to_atom(0x2), do: :select
def group_type_flags_to_atom(0x4), do: :indirect
def group_type_flags_to_atom(0x8), do: :fast_failover
def group_type_flags_to_atom(_), do: throw(:bad_enum)
def group_id_to_int(:max), do: 0xFFFFFF00 def group_id_to_int(:max), do: 0xFFFFFF00
def group_id_to_int(:all), do: 0xFFFFFFFC def group_id_to_int(:all), do: 0xFFFFFFFC
def group_id_to_int(:any), do: 0xFFFFFFFF def group_id_to_int(:any), do: 0xFFFFFFFF
@ -11971,6 +12297,50 @@ defmodule Openflow.Enums do
def action_type_to_atom(0x1F), do: Openflow.Action.ValidateSequence def action_type_to_atom(0x1F), do: Openflow.Action.ValidateSequence
def action_type_to_atom(0xFFFF), do: Openflow.Action.Experimenter def action_type_to_atom(0xFFFF), do: Openflow.Action.Experimenter
def action_type_to_atom(_), do: throw(:bad_enum) def action_type_to_atom(_), do: throw(:bad_enum)
def action_flags_to_int(Openflow.Action.Output), do: 0x1
def action_flags_to_int(Openflow.Action.CopyTtlOut), do: 0x800
def action_flags_to_int(Openflow.Action.CopyTtlIn), do: 0x1000
def action_flags_to_int(Openflow.Action.SetMplsTtl), do: 0x8000
def action_flags_to_int(Openflow.Action.DecMplsTtl), do: 0x10000
def action_flags_to_int(Openflow.Action.PushVlan), do: 0x20000
def action_flags_to_int(Openflow.Action.PopVlan), do: 0x40000
def action_flags_to_int(Openflow.Action.PushMpls), do: 0x80000
def action_flags_to_int(Openflow.Action.PopMpls), do: 0x100000
def action_flags_to_int(Openflow.Action.SetQueue), do: 0x200000
def action_flags_to_int(Openflow.Action.Group), do: 0x400000
def action_flags_to_int(Openflow.Action.SetNwTtl), do: 0x800000
def action_flags_to_int(Openflow.Action.DecNwTtl), do: 0x1000000
def action_flags_to_int(Openflow.Action.SetField), do: 0x2000000
def action_flags_to_int(Openflow.Action.PushPbb), do: 0x4000000
def action_flags_to_int(Openflow.Action.PopPbb), do: 0x8000000
def action_flags_to_int(Openflow.Action.Encap), do: 0x10000000
def action_flags_to_int(Openflow.Action.Decap), do: 0x20000000
def action_flags_to_int(Openflow.Action.SetSequence), do: 0x40000000
def action_flags_to_int(Openflow.Action.ValidateSequence), do: 0x80000000
def action_flags_to_int(Openflow.Action.Experimenter), do: 0xFFFF
def action_flags_to_int(_), do: throw(:bad_enum)
def action_flags_to_atom(0x1), do: Openflow.Action.Output
def action_flags_to_atom(0x800), do: Openflow.Action.CopyTtlOut
def action_flags_to_atom(0x1000), do: Openflow.Action.CopyTtlIn
def action_flags_to_atom(0x8000), do: Openflow.Action.SetMplsTtl
def action_flags_to_atom(0x10000), do: Openflow.Action.DecMplsTtl
def action_flags_to_atom(0x20000), do: Openflow.Action.PushVlan
def action_flags_to_atom(0x40000), do: Openflow.Action.PopVlan
def action_flags_to_atom(0x80000), do: Openflow.Action.PushMpls
def action_flags_to_atom(0x100000), do: Openflow.Action.PopMpls
def action_flags_to_atom(0x200000), do: Openflow.Action.SetQueue
def action_flags_to_atom(0x400000), do: Openflow.Action.Group
def action_flags_to_atom(0x800000), do: Openflow.Action.SetNwTtl
def action_flags_to_atom(0x1000000), do: Openflow.Action.DecNwTtl
def action_flags_to_atom(0x2000000), do: Openflow.Action.SetField
def action_flags_to_atom(0x4000000), do: Openflow.Action.PushPbb
def action_flags_to_atom(0x8000000), do: Openflow.Action.PopPbb
def action_flags_to_atom(0x10000000), do: Openflow.Action.Encap
def action_flags_to_atom(0x20000000), do: Openflow.Action.Decap
def action_flags_to_atom(0x40000000), do: Openflow.Action.SetSequence
def action_flags_to_atom(0x80000000), do: Openflow.Action.ValidateSequence
def action_flags_to_atom(0xFFFF), do: Openflow.Action.Experimenter
def action_flags_to_atom(_), do: throw(:bad_enum)
def action_vendor_to_int(:nicira_ext_action), do: 0x2320 def action_vendor_to_int(:nicira_ext_action), do: 0x2320
def action_vendor_to_int(:onf_ext_action), do: 0x4F4E4600 def action_vendor_to_int(:onf_ext_action), do: 0x4F4E4600
def action_vendor_to_int(_), do: throw(:bad_enum) def action_vendor_to_int(_), do: throw(:bad_enum)
@ -12570,6 +12940,10 @@ defmodule Openflow.Enums do
Openflow.Utils.int_to_flags([], int, enum_of(:group_type)) Openflow.Utils.int_to_flags([], int, enum_of(:group_type))
end end
def int_to_flags(int, :group_type_flags) do
Openflow.Utils.int_to_flags([], int, enum_of(:group_type_flags))
end
def int_to_flags(int, :group_id) do def int_to_flags(int, :group_id) do
Openflow.Utils.int_to_flags([], int, enum_of(:group_id)) Openflow.Utils.int_to_flags([], int, enum_of(:group_id))
end end
@ -12610,6 +12984,10 @@ defmodule Openflow.Enums do
Openflow.Utils.int_to_flags([], int, enum_of(:action_type)) Openflow.Utils.int_to_flags([], int, enum_of(:action_type))
end end
def int_to_flags(int, :action_flags) do
Openflow.Utils.int_to_flags([], int, enum_of(:action_flags))
end
def int_to_flags(int, :action_vendor) do def int_to_flags(int, :action_vendor) do
Openflow.Utils.int_to_flags([], int, enum_of(:action_vendor)) Openflow.Utils.int_to_flags([], int, enum_of(:action_vendor))
end end
@ -12950,6 +13328,10 @@ defmodule Openflow.Enums do
Openflow.Utils.flags_to_int(0, flags, enum_of(:group_type)) Openflow.Utils.flags_to_int(0, flags, enum_of(:group_type))
end end
def flags_to_int(flags, :group_type_flags) do
Openflow.Utils.flags_to_int(0, flags, enum_of(:group_type_flags))
end
def flags_to_int(flags, :group_id) do def flags_to_int(flags, :group_id) do
Openflow.Utils.flags_to_int(0, flags, enum_of(:group_id)) Openflow.Utils.flags_to_int(0, flags, enum_of(:group_id))
end end
@ -12990,6 +13372,10 @@ defmodule Openflow.Enums do
Openflow.Utils.flags_to_int(0, flags, enum_of(:action_type)) Openflow.Utils.flags_to_int(0, flags, enum_of(:action_type))
end end
def flags_to_int(flags, :action_flags) do
Openflow.Utils.flags_to_int(0, flags, enum_of(:action_flags))
end
def flags_to_int(flags, :action_vendor) do def flags_to_int(flags, :action_vendor) do
Openflow.Utils.flags_to_int(0, flags, enum_of(:action_vendor)) Openflow.Utils.flags_to_int(0, flags, enum_of(:action_vendor))
end end
@ -13772,6 +14158,7 @@ defmodule Openflow.Enums do
defp enum_of(:port_reason_mask), do: [add: 1, delete: 2, modify: 4] defp enum_of(:port_reason_mask), do: [add: 1, delete: 2, modify: 4]
defp enum_of(:group_mod_command), do: [add: 0, modify: 1, delete: 2] defp enum_of(:group_mod_command), do: [add: 0, modify: 1, delete: 2]
defp enum_of(:group_type), do: [all: 0, select: 1, indirect: 2, fast_failover: 3] defp enum_of(:group_type), do: [all: 0, select: 1, indirect: 2, fast_failover: 3]
defp enum_of(:group_type_flags), do: [all: 1, select: 2, indirect: 4, fast_failover: 8]
defp enum_of(:group_id), do: [max: 4_294_967_040, all: 4_294_967_292, any: 4_294_967_295] defp enum_of(:group_id), do: [max: 4_294_967_040, all: 4_294_967_292, any: 4_294_967_295]
defp enum_of(:group_capabilities), defp enum_of(:group_capabilities),
@ -13833,6 +14220,31 @@ defmodule Openflow.Enums do
{Openflow.Action.Experimenter, 65535} {Openflow.Action.Experimenter, 65535}
] ]
defp enum_of(:action_flags),
do: [
{Openflow.Action.Output, 1},
{Openflow.Action.CopyTtlOut, 2048},
{Openflow.Action.CopyTtlIn, 4096},
{Openflow.Action.SetMplsTtl, 32768},
{Openflow.Action.DecMplsTtl, 65536},
{Openflow.Action.PushVlan, 131_072},
{Openflow.Action.PopVlan, 262_144},
{Openflow.Action.PushMpls, 524_288},
{Openflow.Action.PopMpls, 1_048_576},
{Openflow.Action.SetQueue, 2_097_152},
{Openflow.Action.Group, 4_194_304},
{Openflow.Action.SetNwTtl, 8_388_608},
{Openflow.Action.DecNwTtl, 16_777_216},
{Openflow.Action.SetField, 33_554_432},
{Openflow.Action.PushPbb, 67_108_864},
{Openflow.Action.PopPbb, 134_217_728},
{Openflow.Action.Encap, 268_435_456},
{Openflow.Action.Decap, 536_870_912},
{Openflow.Action.SetSequence, 1_073_741_824},
{Openflow.Action.ValidateSequence, 2_147_483_648},
{Openflow.Action.Experimenter, 65535}
]
defp enum_of(:action_vendor), do: [nicira_ext_action: 8992, onf_ext_action: 1_330_529_792] defp enum_of(:action_vendor), do: [nicira_ext_action: 8992, onf_ext_action: 1_330_529_792]
defp enum_of(:onf_ext_action), do: [{Openflow.Action.OnfCopyField, 3200}] defp enum_of(:onf_ext_action), do: [{Openflow.Action.OnfCopyField, 3200}]

View file

@ -4,6 +4,7 @@ defmodule Openflow.Multipart.GroupDesc.Reply do
xid: 0, xid: 0,
# virtual field # virtual field
datapath_id: nil, datapath_id: nil,
aux_id: nil,
flags: [], flags: [],
groups: [] groups: []
) )

View file

@ -4,11 +4,20 @@ defmodule Openflow.Multipart.GroupDesc.Request do
xid: 0, xid: 0,
# virtual field # virtual field
datapath_id: nil, datapath_id: nil,
aux_id: nil,
flags: [] flags: []
) )
alias __MODULE__ alias __MODULE__
@type t :: %Request{
version: 4,
datapath_id: String.t(),
aux_id: 0..0xFF | nil,
xid: 0..0xFFFFFFFF,
flags: [:more]
}
def ofp_type, do: 18 def ofp_type, do: 18
def new(xid \\ 0) do def new(xid \\ 0) do

View file

@ -19,29 +19,29 @@ defmodule Openflow.Multipart.GroupFeatures.Reply do
) )
alias __MODULE__ alias __MODULE__
alias Openflow.Enums
def ofp_type, do: 18 def ofp_type, do: 18
def read( def read(
<<types_int::32, capabilities_int::32, max_groups_for_all_int::32, <<types_int::32, capabilities_int::32, max_groups_for_all::32, max_groups_for_select::32,
max_groups_for_select_int::32, max_groups_for_indirect_int::32, max_groups_for_indirect::32, max_groups_for_fast_failover::32, actions_for_all_int::32,
max_groups_for_fast_failover_int::32, actions_for_all_int::32,
actions_for_select_int::32, actions_for_indirect_int::32, actions_for_select_int::32, actions_for_indirect_int::32,
actions_for_fast_failover_int::32>> actions_for_fast_failover_int::32>>
) do ) do
capabilities = Openflow.Enums.int_to_flags(capabilities_int, :group_capabilities) capabilities = Openflow.Enums.int_to_flags(capabilities_int, :group_capabilities)
%Reply{ %Reply{
types: types_int, types: Enums.int_to_flags(types_int, :group_type_flags),
capabilities: capabilities, capabilities: capabilities,
max_groups_for_all: max_groups_for_all_int, max_groups_for_all: max_groups_for_all,
max_groups_for_select: max_groups_for_select_int, max_groups_for_select: max_groups_for_select,
max_groups_for_indirect: max_groups_for_indirect_int, max_groups_for_indirect: max_groups_for_indirect,
max_groups_for_fast_failover: max_groups_for_fast_failover_int, max_groups_for_fast_failover: max_groups_for_fast_failover,
actions_for_all: actions_for_all_int, actions_for_all: Enums.int_to_flags(actions_for_all_int, :action_flags),
actions_for_select: actions_for_select_int, actions_for_select: Enums.int_to_flags(actions_for_select_int, :action_flags),
actions_for_indirect: actions_for_indirect_int, actions_for_indirect: Enums.int_to_flags(actions_for_indirect_int, :action_flags),
actions_for_fast_failover: actions_for_fast_failover_int actions_for_fast_failover: Enums.int_to_flags(actions_for_fast_failover_int, :action_flags)
} }
end end
end end

View file

@ -4,22 +4,28 @@ defmodule Openflow.Multipart.GroupFeatures.Request do
xid: 0, xid: 0,
# virtual field # virtual field
datapath_id: nil, datapath_id: nil,
aux_id: nil,
flags: [] flags: []
) )
alias __MODULE__ alias __MODULE__
@type t :: %Request{
version: 4,
datapath_id: String.t(),
aux_id: 0..0xFF | nil,
xid: 0..0xFFFFFFFF
}
@spec ofp_type() :: 18
def ofp_type, do: 18 def ofp_type, do: 18
def new(xid \\ 0) do @spec new(xid :: 0..0xFFFFFFFF) :: t()
%Request{xid: xid} def new(xid \\ 0), do: %Request{xid: xid}
end
def read("") do @spec read(<<>>) :: t()
%Request{} def read(""), do: %Request{}
end
def to_binary(%Request{} = msg) do @spec to_binary(t()) :: binary()
Openflow.Multipart.Request.header(msg) def to_binary(%Request{} = msg), do: Openflow.Multipart.Request.header(msg)
end
end end

View file

@ -399,73 +399,73 @@ enums = [
tun_metadata16: 56, tun_metadata16: 56,
tun_metadata17: 57, tun_metadata17: 57,
tun_metadata18: 58, tun_metadata18: 58,
tun_metadata19: 59, tun_metadata19: 59,
tun_metadata20: 60, tun_metadata20: 60,
tun_metadata21: 61, tun_metadata21: 61,
tun_metadata22: 62, tun_metadata22: 62,
tun_metadata23: 63, tun_metadata23: 63,
tun_metadata24: 64, tun_metadata24: 64,
tun_metadata25: 65, tun_metadata25: 65,
tun_metadata26: 66, tun_metadata26: 66,
tun_metadata27: 67, tun_metadata27: 67,
tun_metadata28: 68, tun_metadata28: 68,
tun_metadata29: 69, tun_metadata29: 69,
tun_metadata30: 70, tun_metadata30: 70,
tun_metadata31: 71, tun_metadata31: 71,
tun_metadata32: 72, tun_metadata32: 72,
tun_metadata33: 73, tun_metadata33: 73,
tun_metadata34: 74, tun_metadata34: 74,
tun_metadata35: 75, tun_metadata35: 75,
tun_metadata36: 76, tun_metadata36: 76,
tun_metadata37: 77, tun_metadata37: 77,
tun_metadata38: 78, tun_metadata38: 78,
tun_metadata39: 79, tun_metadata39: 79,
tun_metadata40: 80, tun_metadata40: 80,
tun_metadata41: 81, tun_metadata41: 81,
tun_metadata42: 82, tun_metadata42: 82,
tun_metadata43: 83, tun_metadata43: 83,
tun_metadata44: 84, tun_metadata44: 84,
tun_metadata45: 85, tun_metadata45: 85,
tun_metadata46: 86, tun_metadata46: 86,
tun_metadata47: 87, tun_metadata47: 87,
tun_metadata48: 88, tun_metadata48: 88,
tun_metadata49: 89, tun_metadata49: 89,
tun_metadata50: 90, tun_metadata50: 90,
tun_metadata51: 91, tun_metadata51: 91,
tun_metadata52: 92, tun_metadata52: 92,
tun_metadata53: 93, tun_metadata53: 93,
tun_metadata54: 94, tun_metadata54: 94,
tun_metadata55: 95, tun_metadata55: 95,
tun_metadata56: 96, tun_metadata56: 96,
tun_metadata57: 97, tun_metadata57: 97,
tun_metadata58: 98, tun_metadata58: 98,
tun_metadata59: 99, tun_metadata59: 99,
tun_metadata60: 100, tun_metadata60: 100,
tun_metadata61: 101, tun_metadata61: 101,
tun_metadata62: 102, tun_metadata62: 102,
tun_metadata63: 103, tun_metadata63: 103,
tun_flags: 104, tun_flags: 104,
ct_state: 105, ct_state: 105,
ct_zone: 106, ct_zone: 106,
ct_mark: 107, ct_mark: 107,
ct_label: 108, ct_label: 108,
tun_ipv6_src: 109, tun_ipv6_src: 109,
tun_ipv6_dst: 110, tun_ipv6_dst: 110,
xxreg0: 111, xxreg0: 111,
xxreg1: 112, xxreg1: 112,
xxreg2: 113, xxreg2: 113,
xxreg3: 114, xxreg3: 114,
xxreg4: 115, xxreg4: 115,
xxreg5: 116, xxreg5: 116,
xxreg6: 117, xxreg6: 117,
xxreg7: 118, xxreg7: 118,
ct_nw_proto: 119, ct_nw_proto: 119,
ct_nw_src: 120, ct_nw_src: 120,
ct_nw_dst: 121, ct_nw_dst: 121,
ct_ipv6_src: 122, ct_ipv6_src: 122,
ct_ipv6_dst: 123, ct_ipv6_dst: 123,
ct_tp_src: 124, ct_tp_src: 124,
ct_tp_dst: 125 ct_tp_dst: 125
], ],
openflow_basic: [ openflow_basic: [
in_port: 0, in_port: 0,
@ -528,15 +528,15 @@ ct_tp_dst: 125
mpls_pw_metadata: 56, mpls_pw_metadata: 56,
mpls_cw_flags: 57, mpls_cw_flags: 57,
mpls_cw_fragment: 58, mpls_cw_fragment: 58,
mpls_cw_len: 59, mpls_cw_len: 59,
mpls_cw_seq_num: 60, mpls_cw_seq_num: 60,
gtpu_flags: 61, gtpu_flags: 61,
gtpu_ver: 62, gtpu_ver: 62,
gtpu_msg_type: 63, gtpu_msg_type: 63,
gtpu_teid: 64, gtpu_teid: 64,
gtpu_extn_hdr: 65, gtpu_extn_hdr: 65,
gtpu_extn_udp_port: 66, gtpu_extn_udp_port: 66,
gtpu_extn_sci: 67 gtpu_extn_sci: 67
], ],
vlan_id: [ vlan_id: [
present: 0x1000, present: 0x1000,
@ -745,6 +745,12 @@ gtpu_extn_sci: 67
indirect: 2, indirect: 2,
fast_failover: 3 fast_failover: 3
], ],
group_type_flags: [
all: 1 <<< 0,
select: 1 <<< 1,
indirect: 1 <<< 2,
fast_failover: 1 <<< 3
],
group_id: [ group_id: [
max: 0xFFFFFF00, max: 0xFFFFFF00,
all: 0xFFFFFFFC, all: 0xFFFFFFFC,
@ -756,44 +762,44 @@ gtpu_extn_sci: 67
chaining: 1 <<< 2, chaining: 1 <<< 2,
chaining_checks: 1 <<< 3 chaining_checks: 1 <<< 3
], ],
table_id: [ table_id: [
max: 0xFE, max: 0xFE,
all: 0xFF all: 0xFF
], ],
queue_id: [ queue_id: [
all: 0xFFFFFFFF all: 0xFFFFFFFF
], ],
meter_mod_command: [ meter_mod_command: [
add: 0, add: 0,
modify: 1, modify: 1,
delete: 2 delete: 2
], ],
meter_id: [ meter_id: [
max: 0xFFFF0000, max: 0xFFFF0000,
slowpath: 0xFFFFFFFD, slowpath: 0xFFFFFFFD,
controller: 0xFFFFFFFE, controller: 0xFFFFFFFE,
all: 0xFFFFFFFF all: 0xFFFFFFFF
], ],
meter_flags: [ meter_flags: [
kbps: 1 <<< 0, kbps: 1 <<< 0,
pktps: 1 <<< 1, pktps: 1 <<< 1,
burst: 1 <<< 2, burst: 1 <<< 2,
stats: 1 <<< 3 stats: 1 <<< 3
], ],
meter_band_type: [ meter_band_type: [
{Openflow.MeterBand.Drop, 1}, {Openflow.MeterBand.Drop, 1},
{Openflow.MeterBand.Remark, 2}, {Openflow.MeterBand.Remark, 2},
{Openflow.MeterBand.Experimenter, 0xFFFF} {Openflow.MeterBand.Experimenter, 0xFFFF}
], ],
table_config: [ table_config: [
table_miss_controller: 0 <<< 0, table_miss_controller: 0 <<< 0,
table_miss_continue: 1 <<< 0, table_miss_continue: 1 <<< 0,
table_miss_drop: 2 <<< 0, table_miss_drop: 2 <<< 0,
table_miss_mask: 3 <<< 0, table_miss_mask: 3 <<< 0,
eviction: 1 <<< 2, eviction: 1 <<< 2,
vacancy_events: 1 <<< 3 vacancy_events: 1 <<< 3
], ],
action_type: [ action_type: [
{Openflow.Action.Output, 0}, {Openflow.Action.Output, 0},
{Openflow.Action.CopyTtlOut, 11}, {Openflow.Action.CopyTtlOut, 11},
{Openflow.Action.CopyTtlIn, 12}, {Openflow.Action.CopyTtlIn, 12},
@ -815,15 +821,38 @@ action_type: [
{Openflow.Action.SetSequence, 30}, {Openflow.Action.SetSequence, 30},
{Openflow.Action.ValidateSequence, 31}, {Openflow.Action.ValidateSequence, 31},
{Openflow.Action.Experimenter, 0xFFFF} {Openflow.Action.Experimenter, 0xFFFF}
], ],
action_vendor: [ action_flags: [
{Openflow.Action.Output, 1 <<< 0},
{Openflow.Action.CopyTtlOut, 1 <<< 11},
{Openflow.Action.CopyTtlIn, 1 <<< 12},
{Openflow.Action.SetMplsTtl, 1 <<< 15},
{Openflow.Action.DecMplsTtl, 1 <<< 16},
{Openflow.Action.PushVlan, 1 <<< 17},
{Openflow.Action.PopVlan, 1 <<< 18},
{Openflow.Action.PushMpls, 1 <<< 19},
{Openflow.Action.PopMpls, 1 <<< 20},
{Openflow.Action.SetQueue, 1 <<< 21},
{Openflow.Action.Group, 1 <<< 22},
{Openflow.Action.SetNwTtl, 1 <<< 23},
{Openflow.Action.DecNwTtl, 1 <<< 24},
{Openflow.Action.SetField, 1 <<< 25},
{Openflow.Action.PushPbb, 1 <<< 26},
{Openflow.Action.PopPbb, 1 <<< 27},
{Openflow.Action.Encap, 1 <<< 28},
{Openflow.Action.Decap, 1 <<< 29},
{Openflow.Action.SetSequence, 1 <<< 30},
{Openflow.Action.ValidateSequence, 1 <<< 31},
{Openflow.Action.Experimenter, 0xFFFF}
],
action_vendor: [
nicira_ext_action: 0x00002320, nicira_ext_action: 0x00002320,
onf_ext_action: 0x4F4E4600 onf_ext_action: 0x4F4E4600
], ],
onf_ext_action: [ onf_ext_action: [
{Openflow.Action.OnfCopyField, 3200} {Openflow.Action.OnfCopyField, 3200}
], ],
nicira_ext_action: [ nicira_ext_action: [
{Openflow.Action.NxResubmit, 1}, {Openflow.Action.NxResubmit, 1},
{Openflow.Action.NxSetTunnel, 2}, {Openflow.Action.NxSetTunnel, 2},
# {Openflow.Action.NxSetQueue, 4}, Deprecated # {Openflow.Action.NxSetQueue, 4}, Deprecated
@ -870,67 +899,67 @@ nicira_ext_action: [
{Openflow.Action.NxEncap, 46}, {Openflow.Action.NxEncap, 46},
{Openflow.Action.NxDecap, 47}, {Openflow.Action.NxDecap, 47},
{Openflow.Action.NxDebugRecirc, 0xFF} {Openflow.Action.NxDebugRecirc, 0xFF}
], ],
nx_mp_algorithm: [ nx_mp_algorithm: [
modulo_n: 0, modulo_n: 0,
hash_threshold: 1, hash_threshold: 1,
highest_random_weight: 2, highest_random_weight: 2,
iterative_hash: 3 iterative_hash: 3
], ],
nx_hash_fields: [ nx_hash_fields: [
eth_src: 0, eth_src: 0,
symmetric_l4: 1, symmetric_l4: 1,
symmetric_l3l4: 2, symmetric_l3l4: 2,
symmetric_l3l4_udp: 3, symmetric_l3l4_udp: 3,
nw_src: 4, nw_src: 4,
nw_dst: 5 nw_dst: 5
], ],
nx_bd_algorithm: [ nx_bd_algorithm: [
active_backup: 0, active_backup: 0,
highest_random_weight: 1 highest_random_weight: 1
], ],
nx_learn_flag: [ nx_learn_flag: [
send_flow_rem: 1 <<< 0, send_flow_rem: 1 <<< 0,
delete_learned: 1 <<< 1, delete_learned: 1 <<< 1,
write_result: 1 <<< 2 write_result: 1 <<< 2
], ],
nx_conntrack_flags: [ nx_conntrack_flags: [
commit: 1 <<< 0, commit: 1 <<< 0,
force: 1 <<< 1 force: 1 <<< 1
], ],
nx_nat_flags: [ nx_nat_flags: [
src: 1 <<< 0, src: 1 <<< 0,
dst: 1 <<< 1, dst: 1 <<< 1,
persistent: 1 <<< 2, persistent: 1 <<< 2,
protocol_hash: 1 <<< 3, protocol_hash: 1 <<< 3,
protocol_random: 1 <<< 4 protocol_random: 1 <<< 4
], ],
nx_nat_range: [ nx_nat_range: [
ipv4_min: 1 <<< 0, ipv4_min: 1 <<< 0,
ipv4_max: 1 <<< 1, ipv4_max: 1 <<< 1,
ipv6_min: 1 <<< 2, ipv6_min: 1 <<< 2,
ipv6_max: 1 <<< 3, ipv6_max: 1 <<< 3,
proto_min: 1 <<< 4, proto_min: 1 <<< 4,
proto_max: 1 <<< 5 proto_max: 1 <<< 5
], ],
nx_action_controller2_prop_type: [ nx_action_controller2_prop_type: [
max_len: 0, max_len: 0,
controller_id: 1, controller_id: 1,
reason: 2, reason: 2,
userdata: 3, userdata: 3,
pause: 4 pause: 4
], ],
nx_action_sample_direction: [ nx_action_sample_direction: [
default: 0, default: 0,
ingress: 1, ingress: 1,
egress: 2 egress: 2
], ],
nx_flow_spec_type: [ nx_flow_spec_type: [
{Openflow.Action.NxFlowSpecMatch, 0}, {Openflow.Action.NxFlowSpecMatch, 0},
{Openflow.Action.NxFlowSpecLoad, 1}, {Openflow.Action.NxFlowSpecLoad, 1},
{Openflow.Action.NxFlowSpecOutput, 2} {Openflow.Action.NxFlowSpecOutput, 2}
], ],
instruction_type: [ instruction_type: [
{Openflow.Instruction.GotoTable, 1}, {Openflow.Instruction.GotoTable, 1},
{Openflow.Instruction.WriteMetadata, 2}, {Openflow.Instruction.WriteMetadata, 2},
{Openflow.Instruction.WriteActions, 3}, {Openflow.Instruction.WriteActions, 3},
@ -938,28 +967,28 @@ instruction_type: [
{Openflow.Instruction.ClearActions, 5}, {Openflow.Instruction.ClearActions, 5},
{Openflow.Instruction.Meter, 6}, {Openflow.Instruction.Meter, 6},
{Openflow.Instruction.Experimenter, 0xFFFF} {Openflow.Instruction.Experimenter, 0xFFFF}
], ],
controller_role: [ controller_role: [
nochange: 0, nochange: 0,
equal: 1, equal: 1,
master: 2, master: 2,
slave: 3 slave: 3
], ],
nx_role: [ nx_role: [
other: 0, other: 0,
master: 1, master: 1,
slave: 2 slave: 2
], ],
packet_in_format: [ packet_in_format: [
standard: 0, standard: 0,
nxt_packet_in: 1, nxt_packet_in: 1,
nxt_packet_in2: 2 nxt_packet_in2: 2
], ],
flow_format: [ flow_format: [
openflow10: 0, openflow10: 0,
nxm: 1 nxm: 1
], ],
packet_in2_prop_type: [ packet_in2_prop_type: [
packet: 0, packet: 0,
full_len: 1, full_len: 1,
buffer_id: 2, buffer_id: 2,
@ -969,8 +998,8 @@ packet_in2_prop_type: [
metadata: 6, metadata: 6,
userdata: 7, userdata: 7,
continuation: 8 continuation: 8
], ],
continuation_prop_type: [ continuation_prop_type: [
bridge: 0x8000, bridge: 0x8000,
stack: 0x8001, stack: 0x8001,
mirrors: 0x8002, mirrors: 0x8002,
@ -979,27 +1008,27 @@ continuation_prop_type: [
cookie: 0x8005, cookie: 0x8005,
actions: 0x8006, actions: 0x8006,
action_set: 0x8007 action_set: 0x8007
], ],
flow_monitor_flag: [ flow_monitor_flag: [
initial: 1 <<< 0, initial: 1 <<< 0,
add: 1 <<< 1, add: 1 <<< 1,
delete: 1 <<< 2, delete: 1 <<< 2,
modify: 1 <<< 3, modify: 1 <<< 3,
actions: 1 <<< 4, actions: 1 <<< 4,
own: 1 <<< 5 own: 1 <<< 5
], ],
flow_update_event: [ flow_update_event: [
added: 0, added: 0,
deleted: 1, deleted: 1,
modified: 2, modified: 2,
abbrev: 3 abbrev: 3
], ],
tlv_table_mod_command: [ tlv_table_mod_command: [
add: 0, add: 0,
delete: 1, delete: 1,
clear: 2 clear: 2
], ],
table_feature_prop_type: [ table_feature_prop_type: [
instructions: 0, instructions: 0,
instructions_miss: 1, instructions_miss: 1,
next_tables: 2, next_tables: 2,
@ -1016,8 +1045,8 @@ table_feature_prop_type: [
apply_setfield_miss: 15, apply_setfield_miss: 15,
experimenter: 0xFFFE, experimenter: 0xFFFE,
experimenter_miss: 0xFFFF experimenter_miss: 0xFFFF
], ],
bundle_ctrl_type: [ bundle_ctrl_type: [
open_request: 0, open_request: 0,
open_reply: 1, open_reply: 1,
close_request: 2, close_request: 2,
@ -1026,11 +1055,11 @@ bundle_ctrl_type: [
commit_reply: 5, commit_reply: 5,
discard_request: 6, discard_request: 6,
discard_reply: 7 discard_reply: 7
], ],
bundle_flags: [ bundle_flags: [
atomic: 1 <<< 0, atomic: 1 <<< 0,
ordered: 1 <<< 1 ordered: 1 <<< 1
] ]
] ]
File.write( File.write(
@ -1068,9 +1097,9 @@ for {enum_name, enum_def} <- enums do
""", """,
[:append, :binary] [:append, :binary]
) )
end end
for {enum_name, enum_def} <- enums do for {enum_name, enum_def} <- enums do
to_atom_fn_name = :"#{enum_name}_to_atom" to_atom_fn_name = :"#{enum_name}_to_atom"
for {_key, value} <- enum_def do for {_key, value} <- enum_def do
@ -1096,9 +1125,9 @@ for {enum_name, enum_def} <- enums do
""", """,
[:append, :binary] [:append, :binary]
) )
end end
for {enum_name, enum_def} <- enums do for {enum_name, enum_def} <- enums do
to_int_fn_name = :"#{enum_name}_to_int" to_int_fn_name = :"#{enum_name}_to_int"
to_atom_fn_name = :"#{enum_name}_to_atom" to_atom_fn_name = :"#{enum_name}_to_atom"
@ -1133,9 +1162,9 @@ for {enum_name, enum_def} <- enums do
:append, :append,
:binary :binary
]) ])
end end
for {enum_name, _enum_def} <- enums do for {enum_name, _enum_def} <- enums do
File.write( File.write(
"lib/openflow/enums.ex", "lib/openflow/enums.ex",
""" """
@ -1145,9 +1174,9 @@ for {enum_name, enum_def} <- enums do
""", """,
[:append, :binary] [:append, :binary]
) )
end end
for {enum_name, _enum_def} <- enums do for {enum_name, _enum_def} <- enums do
File.write( File.write(
"lib/openflow/enums.ex", "lib/openflow/enums.ex",
""" """
@ -1157,15 +1186,14 @@ for {enum_name, enum_def} <- enums do
""", """,
[:append, :binary] [:append, :binary]
) )
end end
for {enum_name, enum_def} <- enums do for {enum_name, enum_def} <- enums do
File.write( File.write(
"lib/openflow/enums.ex", "lib/openflow/enums.ex",
" defp enum_of(:#{enum_name}), do: #{inspect(enum_def, pretty: true, limit: 100_000)}\n", " defp enum_of(:#{enum_name}), do: #{inspect(enum_def, pretty: true, limit: 100_000)}\n",
[:append, :binary] [:append, :binary]
) )
end end
File.write("lib/openflow/enums.ex", "end", [:append, :binary])
File.write("lib/openflow/enums.ex", "end", [:append, :binary])

View file

@ -0,0 +1,50 @@
defmodule OfpGroupDescTest do
use ExUnit.Case
describe "Openflow.Multipart.GroupDesc.Request" do
test "with default values" do
desc = Openflow.Multipart.GroupDesc.Request.new(0)
desc
|> Openflow.to_binary()
|> Openflow.read()
|> Kernel.elem(1)
|> Kernel.==(desc)
|> assert()
end
end
describe "Openflow.Multipart.GroupDesc.Reply" do
test "with test packet_data" do
group_desc_stats =
"test/packet_data/4-34-ofp_group_desc_reply.packet"
|> File.read!()
|> Openflow.read()
|> Kernel.elem(1)
%Openflow.Multipart.GroupDesc.Reply{
aux_id: nil,
datapath_id: nil,
flags: [],
groups: [
%Openflow.Multipart.GroupDescStats{
buckets: [
%Openflow.Bucket{
actions: [
%Openflow.Action.Output{max_len: :no_buffer, port_number: 2}
],
watch_group: 1,
watch_port: 1,
weight: 1
}
],
group_id: 1,
type: :all
}
],
version: 4,
xid: 0
} = group_desc_stats
end
end
end

View file

@ -0,0 +1,104 @@
defmodule OfpGroupFeaturesTest do
use ExUnit.Case
describe "Openflow.Multipart.GroupFeatures.Request" do
test "with default values" do
features = Openflow.Multipart.GroupFeatures.Request.new(0)
features
|> Openflow.to_binary()
|> Openflow.read()
|> Kernel.elem(1)
|> Kernel.==(features)
|> assert()
end
end
describe "Openflow.Multipart.GroupFeatures.Reply" do
test "with test packet_data" do
group_features_stats =
"test/packet_data/4-32-ofp_group_features_reply.packet"
|> File.read!()
|> Openflow.read()
|> Kernel.elem(1)
%Openflow.Multipart.GroupFeatures.Reply{
actions_for_all: [
Openflow.Action.Output,
Openflow.Action.CopyTtlOut,
Openflow.Action.CopyTtlIn,
Openflow.Action.SetMplsTtl,
Openflow.Action.DecMplsTtl,
Openflow.Action.PushVlan,
Openflow.Action.PopVlan,
Openflow.Action.PushMpls,
Openflow.Action.PopMpls,
Openflow.Action.SetQueue,
Openflow.Action.Group,
Openflow.Action.SetNwTtl,
Openflow.Action.DecNwTtl,
Openflow.Action.SetField
],
actions_for_fast_failover: [
Openflow.Action.Output,
Openflow.Action.CopyTtlOut,
Openflow.Action.CopyTtlIn,
Openflow.Action.SetMplsTtl,
Openflow.Action.DecMplsTtl,
Openflow.Action.PushVlan,
Openflow.Action.PopVlan,
Openflow.Action.PushMpls,
Openflow.Action.PopMpls,
Openflow.Action.SetQueue,
Openflow.Action.Group,
Openflow.Action.SetNwTtl,
Openflow.Action.DecNwTtl,
Openflow.Action.SetField
],
actions_for_indirect: [
Openflow.Action.Output,
Openflow.Action.CopyTtlOut,
Openflow.Action.CopyTtlIn,
Openflow.Action.SetMplsTtl,
Openflow.Action.DecMplsTtl,
Openflow.Action.PushVlan,
Openflow.Action.PopVlan,
Openflow.Action.PushMpls,
Openflow.Action.PopMpls,
Openflow.Action.SetQueue,
Openflow.Action.Group,
Openflow.Action.SetNwTtl,
Openflow.Action.DecNwTtl,
Openflow.Action.SetField
],
actions_for_select: [
Openflow.Action.Output,
Openflow.Action.CopyTtlOut,
Openflow.Action.CopyTtlIn,
Openflow.Action.SetMplsTtl,
Openflow.Action.DecMplsTtl,
Openflow.Action.PushVlan,
Openflow.Action.PopVlan,
Openflow.Action.PushMpls,
Openflow.Action.PopMpls,
Openflow.Action.SetQueue,
Openflow.Action.Group,
Openflow.Action.SetNwTtl,
Openflow.Action.DecNwTtl,
Openflow.Action.SetField
],
aux_id: nil,
capabilities: [:select_weight, :chaining],
datapath_id: nil,
flags: [],
max_groups_for_all: 16_777_216,
max_groups_for_fast_failover: 16_777_216,
max_groups_for_indirect: 16_777_216,
max_groups_for_select: 16_777_216,
types: [:all, :select, :indirect, :fast_failover],
version: 4,
xid: 0
} = group_features_stats
end
end
end