Hide all implementation details deeper than Rule abstraction.

PiperOrigin-RevId: 667367125
This commit is contained in:
Jayden Nyamiaka
2024-08-25 13:48:17 -07:00
committed by gVisor bot
parent e84d53199f
commit bc4a23853e
4 changed files with 402 additions and 402 deletions
+75 -75
View File
@@ -550,48 +550,48 @@ func validateBaseChainInfo(info *BaseChainInfo, family AddressFamily) error {
// Note: Empty rules should be created directly (via &Rule{}).
type Rule struct {
chain *Chain
ops []Operation
ops []operation
}
// Operation represents a single operation in a rule.
type Operation interface {
// operation represents a single operation in a rule.
type operation interface {
// evaluate evaluates the operation on the given packet and register set,
// changing the register set and possibly the packet in place.
evaluate(regs *RegisterSet, pkt *stack.PacketBuffer)
evaluate(regs *registerSet, pkt *stack.PacketBuffer)
}
// Ensures all operations implement the Operation interface at compile time.
var (
_ Operation = (*Immediate)(nil)
_ Operation = (*Comparison)(nil)
_ operation = (*immediate)(nil)
_ operation = (*comparison)(nil)
)
// Immediate is an operation that sets the data in a register.
type Immediate struct {
data RegisterData // Data to set the destination register to.
// immediate is an operation that sets the data in a register.
type immediate struct {
data registerData // Data to set the destination register to.
dreg uint8 // Number of the destination register.
}
// NewImmediate creates a new Immediate operation.
func NewImmediate(dreg uint8, data RegisterData) (*Immediate, error) {
if err := data.ValidateRegister(dreg); err != nil {
// newImmediate creates a new Immediate operation.
func newImmediate(dreg uint8, data registerData) (*immediate, error) {
if err := data.validateRegister(dreg); err != nil {
return nil, err
}
return &Immediate{dreg: dreg, data: data}, nil
return &immediate{dreg: dreg, data: data}, nil
}
// evaluate for Immediate sets the data in the destination register.
func (op Immediate) evaluate(regs *RegisterSet, pkt *stack.PacketBuffer) {
op.data.StoreData(regs, op.dreg)
func (op immediate) evaluate(regs *registerSet, pkt *stack.PacketBuffer) {
op.data.storeData(regs, op.dreg)
}
// Comparison is an operation that compares the data in a register to a given
// comparison is an operation that compares the data in a register to a given
// value and breaks (by setting the verdict register to NFT_BREAK) from the rule
// if the comparison is false.
// Note: comparison operations are not supported for the verdict register.
type Comparison struct {
data RegisterData // Data to compare the source register to.
type comparison struct {
data registerData // Data to compare the source register to.
sreg uint8 // Number of the source register.
cop cmpOp // Comparison operator.
}
@@ -632,26 +632,26 @@ func validateComparisonOp(cop cmpOp) error {
}
}
// NewComparison creates a new Comparison operation.
func NewComparison(sreg uint8, op int, data RegisterData) (*Comparison, error) {
// newComparison creates a new Comparison operation.
func newComparison(sreg uint8, op int, data registerData) (*comparison, error) {
if sreg == linux.NFT_REG_VERDICT {
return nil, fmt.Errorf("comparison operation cannot use verdict register as source")
}
if err := data.ValidateRegister(sreg); err != nil {
if err := data.validateRegister(sreg); err != nil {
return nil, err
}
cop := cmpOp(op)
if err := validateComparisonOp(cop); err != nil {
return nil, err
}
return &Comparison{sreg: sreg, cop: cop, data: data}, nil
return &comparison{sreg: sreg, cop: cop, data: data}, nil
}
// evaluate for Comparison compares the data in the source register to the given
// data and breaks from the rule if the comparison is false.
func (op Comparison) evaluate(regs *RegisterSet, pkt *stack.PacketBuffer) {
func (op comparison) evaluate(regs *registerSet, pkt *stack.PacketBuffer) {
// Gets the data to compare to.
bytesData, ok := op.data.(BytesData)
bytesData, ok := op.data.(bytesData)
if !ok {
panic("comparison operation data is not BytesData")
}
@@ -716,99 +716,99 @@ func isRegister(reg uint8) bool {
return isVerdictRegister(reg) || is16ByteRegister(reg) || is4ByteRegister(reg)
}
// RegisterData represents the data to be set in a register.
type RegisterData interface {
// registerData represents the data to be set in a register.
type registerData interface {
// String returns a string representation of the register data.
String() string
// Equal compares the register data to another.
Equal(other RegisterData) bool
// equal compares the register data to another.
equal(other registerData) bool
// ValidateRegister ensures the register is compatible with the data type,
// validateRegister ensures the register is compatible with the data type,
// returning an error otherwise.
ValidateRegister(reg uint8) error
validateRegister(reg uint8) error
// StoreData sets the data in the destination register, panicking if the
// storeData sets the data in the destination register, panicking if the
// register is not valid for the data type.
// Note: assumes data is valid for register. This is used primarily during
// operation evaluation and the data type/register compatibility should have
// been checked during the operation init.
StoreData(regs *RegisterSet, reg uint8)
storeData(regs *registerSet, reg uint8)
}
// VerdictData represents a verdict as data to be stored in a register.
type VerdictData struct {
// verdictData represents a verdict as data to be stored in a register.
type verdictData struct {
data Verdict
}
// NewVerdictData creates a RegisterData for a verdict.
func NewVerdictData(verdict Verdict) RegisterData { return VerdictData{data: verdict} }
// newVerdictData creates a RegisterData for a verdict.
func newVerdictData(verdict Verdict) registerData { return verdictData{data: verdict} }
// String returns a string representation of the verdict data.
func (rd VerdictData) String() string {
func (rd verdictData) String() string {
return rd.data.String()
}
// Equal compares the verdict data to another RegisterData object.
func (rd VerdictData) Equal(other RegisterData) bool {
// equal compares the verdict data to another RegisterData object.
func (rd verdictData) equal(other registerData) bool {
if other == nil {
return false
}
otherVD, ok := other.(VerdictData)
otherVD, ok := other.(verdictData)
if !ok {
return false
}
return rd.data == otherVD.data
}
// ValidateRegister ensures the register is compatible with VerdictData.
func (rd VerdictData) ValidateRegister(reg uint8) error {
// validateRegister ensures the register is compatible with VerdictData.
func (rd verdictData) validateRegister(reg uint8) error {
if !isVerdictRegister(reg) {
return fmt.Errorf("verdict can only be stored in verdict register")
}
return nil
}
// StoreData sets the data in the destination register to the verdict.
func (rd VerdictData) StoreData(regs *RegisterSet, reg uint8) {
if err := rd.ValidateRegister(reg); err != nil {
// storeData sets the data in the destination register to the verdict.
func (rd verdictData) storeData(regs *registerSet, reg uint8) {
if err := rd.validateRegister(reg); err != nil {
panic(err)
}
regs.verdict = rd.data
}
// BytesData represents data in 4-byte chunks to be stored in a register.
type BytesData struct {
// bytesData represents data in 4-byte chunks to be stored in a register.
type bytesData struct {
data []byte
}
// NewBytesData creates a RegisterData for 4, 8, 12, or 16 bytes of data.
func NewBytesData(bytes []byte) RegisterData {
// newBytesData creates a RegisterData for 4, 8, 12, or 16 bytes of data.
func newBytesData(bytes []byte) registerData {
if len(bytes)%4 != 0 || len(bytes) > 16 {
panic(fmt.Errorf("invalid byte data length: %d", len(bytes)))
}
return BytesData{data: bytes}
return bytesData{data: bytes}
}
// String returns a string representation of the bytes data.
func (rd BytesData) String() string {
func (rd bytesData) String() string {
return fmt.Sprintf("%x", rd.data)
}
// Equal compares the bytes data to another RegisterData object.
func (rd BytesData) Equal(other RegisterData) bool {
// equal compares the bytes data to another RegisterData object.
func (rd bytesData) equal(other registerData) bool {
if other == nil {
return false
}
otherBD, ok := other.(BytesData)
otherBD, ok := other.(bytesData)
if !ok {
return false
}
return slices.Equal(rd.data, otherBD.data)
}
// ValidateRegister ensures the register is compatible with this bytes data.
func (rd BytesData) ValidateRegister(reg uint8) error {
// validateRegister ensures the register is compatible with this bytes data.
func (rd bytesData) validateRegister(reg uint8) error {
if isVerdictRegister(reg) {
return fmt.Errorf("data cannot be stored in verdict register")
}
@@ -823,7 +823,7 @@ func (rd BytesData) ValidateRegister(reg uint8) error {
// register data from the register set.
// Note: does not support verdict data and assumes the register is valid for the
// given data type.
func (rd BytesData) getRegisterBuffer(regs *RegisterSet, reg uint8) []byte {
func (rd bytesData) getRegisterBuffer(regs *registerSet, reg uint8) []byte {
// The entire 4-byte register (data must be exactly 4 bytes)
if is4ByteRegister(reg) {
start := (reg - linux.NFT_REG32_00) * linux.NFT_REG32_SIZE
@@ -835,33 +835,33 @@ func (rd BytesData) getRegisterBuffer(regs *RegisterSet, reg uint8) []byte {
return regs.data[end-len(rd.data) : end]
}
// StoreData sets the data in the destination register to the bytes data.
func (rd BytesData) StoreData(regs *RegisterSet, reg uint8) {
if err := rd.ValidateRegister(reg); err != nil {
// storeData sets the data in the destination register to the bytes data.
func (rd bytesData) storeData(regs *registerSet, reg uint8) {
if err := rd.validateRegister(reg); err != nil {
panic(err)
}
copy(rd.getRegisterBuffer(regs, reg), rd.data)
}
// RegisterSet represents the set of registers supported by the kernel.
// registerSet represents the set of registers supported by the kernel.
// Use RegisterData.StoreData to set data in the registers.
// Note: Corresponds to nft_regs from include/net/netfilter/nf_tables.h.
type RegisterSet struct {
type registerSet struct {
verdict Verdict // 16-byte verdict register
data [registersByteSize]byte // 4 16-byte registers or 16 4-byte registers
}
// NewRegisterSet creates a new RegisterSet with the Continue Verdict and all
// newRegisterSet creates a new RegisterSet with the Continue Verdict and all
// registers set to 0.
func NewRegisterSet() RegisterSet {
return RegisterSet{
func newRegisterSet() registerSet {
return registerSet{
verdict: Verdict{Code: VC(linux.NFT_CONTINUE)},
data: [registersByteSize]byte{0},
}
}
// Verdict returns the verdict data.
func (regs *RegisterSet) Verdict() Verdict {
func (regs *registerSet) Verdict() Verdict {
return regs.verdict
}
@@ -966,7 +966,7 @@ func (nf *NFTables) EvaluateHook(family AddressFamily, hook Hook, pkt *stack.Pac
return Verdict{Code: VC(linux.NF_ACCEPT)}, nil
}
regs := NewRegisterSet()
regs := newRegisterSet()
// Evaluates packet through all base chains for given hook in priority order.
var bc *Chain
@@ -1003,7 +1003,7 @@ func (nf *NFTables) EvaluateHook(family AddressFamily, hook Hook, pkt *stack.Pac
// evaluateFromRule is a helper function for Chain.evaluate that evaluates the
// packet through the rules in the chain starting at the specified rule index.
func (c *Chain) evaluateFromRule(rIdx int, jumpDepth int, regs *RegisterSet, pkt *stack.PacketBuffer) error {
func (c *Chain) evaluateFromRule(rIdx int, jumpDepth int, regs *registerSet, pkt *stack.PacketBuffer) error {
if jumpDepth >= nestedJumpLimit {
return fmt.Errorf("jump stack limit of %d exceeded", nestedJumpLimit)
}
@@ -1060,7 +1060,7 @@ evalLoop:
// evaluate for Chain evaluates the packet through the chain's rules and returns
// the verdict and modifies the packet in place.
func (c *Chain) evaluate(regs *RegisterSet, pkt *stack.PacketBuffer) error {
func (c *Chain) evaluate(regs *registerSet, pkt *stack.PacketBuffer) error {
return c.evaluateFromRule(0, 0, regs, pkt)
}
@@ -1068,7 +1068,7 @@ func (c *Chain) evaluate(regs *RegisterSet, pkt *stack.PacketBuffer) error {
// the register set and possibly the packet in place.
// The verdict in regs.Verdict() may be an nf table internal verdict or a
// netfilter terminal verdict.
func (r *Rule) evaluate(regs *RegisterSet, pkt *stack.PacketBuffer) error {
func (r *Rule) evaluate(regs *registerSet, pkt *stack.PacketBuffer) error {
for _, op := range r.ops {
op.evaluate(regs, pkt)
if regs.Verdict().Code != VC(linux.NFT_CONTINUE) {
@@ -1540,12 +1540,12 @@ func (c *Chain) RuleCount() int {
// isJumpOrGoto returns whether the operation is an immediate operation that
// sets the verdict register to a jump or goto verdict and returns the name of
// the target chain to jump or goto if so.
func isJumpOrGotoOperation(op Operation) (bool, string) {
imm, ok := op.(*Immediate)
func isJumpOrGotoOperation(op operation) (bool, string) {
imm, ok := op.(*immediate)
if !ok {
return false, ""
}
verdictData, ok := imm.data.(VerdictData)
verdictData, ok := imm.data.(verdictData)
if !ok {
return false, ""
}
@@ -1587,10 +1587,10 @@ func (c *Chain) checkLoops(source *Chain) error {
// Rule Functions
//
// AddOperation adds an operation to the rule. Adding operations is only allowed
// addOperation adds an operation to the rule. Adding operations is only allowed
// before the rule is registered to a chain. Returns an error if the operation
// is nil or if the rule is already registered to a chain.
func (r *Rule) AddOperation(op Operation) error {
func (r *Rule) addOperation(op operation) error {
if op == nil {
return fmt.Errorf("operation is nil")
}
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -108,7 +108,7 @@ func InterpretRule(ruleString string) (*Rule, error) {
return s == ""
})
r := &Rule{ops: make([]Operation, 0, len(lines))}
r := &Rule{ops: make([]operation, 0, len(lines))}
// Interprets all operations in the rule.
for lnIdx, line := range lines {
@@ -116,7 +116,7 @@ func InterpretRule(ruleString string) (*Rule, error) {
if err != nil {
return nil, err
}
if err := r.AddOperation(op); err != nil {
if err := r.addOperation(op); err != nil {
return nil, err
}
}
@@ -128,7 +128,7 @@ func InterpretRule(ruleString string) (*Rule, error) {
// assumed to be a single line of text surrounded in square brackets.
// Note: the operation string should be generated as output from the official nft
// binary (can be accomplished by using flag --debug=netlink).
func InterpretOperation(line string, lnIdx int) (Operation, error) {
func InterpretOperation(line string, lnIdx int) (operation, error) {
tokens := strings.Fields(line)
if len(tokens) < 2 {
return nil, &SyntaxError{lnIdx, 0, fmt.Sprintf("incorrect number of tokens for operation, should be at least 2, got %d", len(tokens))}
@@ -146,7 +146,7 @@ func InterpretOperation(line string, lnIdx int) (Operation, error) {
}
// InterpretImmediate creates a new Immediate operation from the given string.
func InterpretImmediate(line string, lnIdx int) (Operation, error) {
func InterpretImmediate(line string, lnIdx int) (operation, error) {
tokens := strings.Fields(line)
// Requires at least 6 tokens:
@@ -193,7 +193,7 @@ func InterpretImmediate(line string, lnIdx int) (Operation, error) {
}
// Create the operation with the specified arguments.
imm, err := NewImmediate(reg, data)
imm, err := newImmediate(reg, data)
if err != nil {
return nil, &LogicError{lnIdx, tkIdx, err}
}
@@ -202,7 +202,7 @@ func InterpretImmediate(line string, lnIdx int) (Operation, error) {
}
// InterpretComparison creates a new Comparison operation from the given string.
func InterpretComparison(line string, lnIdx int) (Operation, error) {
func InterpretComparison(line string, lnIdx int) (operation, error) {
tokens := strings.Fields(line)
// Requires at least 7 tokens:
@@ -256,7 +256,7 @@ func InterpretComparison(line string, lnIdx int) (Operation, error) {
}
// Create the operation with the specified arguments.
cmp, err := NewComparison(reg, cop, data)
cmp, err := newComparison(reg, cop, data)
if err != nil {
return nil, &LogicError{lnIdx, tkIdx, err}
}
@@ -297,14 +297,14 @@ func parseRegister(regString string, lnIdx int, tkIdx int) (uint8, error) {
// parseRegisterData parses the register data from the given token and returns
// the index of the next token to process (can consume multiple tokens).
// Note: assumes the register index is valid (was checked in parseRegister).
func parseRegisterData(reg uint8, tokens []string, lnIdx int, tkIdx int) (int, RegisterData, error) {
func parseRegisterData(reg uint8, tokens []string, lnIdx int, tkIdx int) (int, registerData, error) {
// Handles verdict data.
if isVerdictRegister(reg) {
nextIdx, verdict, err := parseVerdict(tokens, lnIdx, tkIdx)
if err != nil {
return 0, nil, err
}
return nextIdx, NewVerdictData(verdict), nil
return nextIdx, newVerdictData(verdict), nil
}
// Handles hex data (4-, 8-, 12-, or 16-byte).
if len(tokens[tkIdx]) > 1 && tokens[tkIdx][:2] == "0x" {
@@ -314,7 +314,7 @@ func parseRegisterData(reg uint8, tokens []string, lnIdx int, tkIdx int) (int, R
}
// 4-byte data is only valid for 4-byte register. Any byte data can be
// stored in 16-byte registerValidates the register data type.
if err := data.ValidateRegister(reg); err != nil {
if err := data.validateRegister(reg); err != nil {
return 0, nil, &LogicError{lnIdx, tkIdx, err}
}
return nextIdx, data, nil
@@ -367,7 +367,7 @@ func parseVerdict(tokens []string, lnIdx int, tkIdx int) (int, Verdict, error) {
// parseHexData parses little endian hexadecimal data from the given token and
// returns the index of the next token to process (can consume multiple tokens).
func parseHexData(tokens []string, lnIdx int, tkIdx int) (int, RegisterData, error) {
func parseHexData(tokens []string, lnIdx int, tkIdx int) (int, registerData, error) {
var bytes []byte
for ; tkIdx < len(tokens); tkIdx++ {
if len(tokens[tkIdx]) < 2 || tokens[tkIdx][:2] != "0x" {
@@ -388,7 +388,7 @@ func parseHexData(tokens []string, lnIdx int, tkIdx int) (int, RegisterData, err
if len(bytes) > 16 {
return 0, nil, &SyntaxError{lnIdx, tkIdx, fmt.Sprintf("cannot have more than 16 bytes of hexadecimal data, got %d", len(bytes))}
}
return tkIdx, NewBytesData(bytes), nil
return tkIdx, newBytesData(bytes), nil
}
// parseCmpOp parses the int representing the cmpOp from the given string.
+53 -53
View File
@@ -24,12 +24,12 @@ import (
type interpretOperationTestAction struct {
tname string
opStr string
expected Operation // will be nil if an error is expected
expected operation // will be nil if an error is expected
}
// checkOp is a generic operation validation function used for testing that
// the interpretation of an operation matches the expected operation.
func checkOp(t *testing.T, test interpretOperationTestAction, checkFunc func(string, Operation, Operation) error) {
func checkOp(t *testing.T, test interpretOperationTestAction, checkFunc func(string, operation, operation) error) {
rule, err := InterpretRule(test.opStr)
if test.expected == nil {
if err == nil {
@@ -58,32 +58,32 @@ func TestInterpretImmediateOps(t *testing.T) {
{
tname: "verdict register with accept verdict",
opStr: "[ immediate reg 0 accept ]",
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, NewVerdictData(Verdict{Code: VC(linux.NF_ACCEPT)})),
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NF_ACCEPT)})),
},
{
tname: "verdict register with drop verdict",
opStr: "[ immediate reg 0 drop ]",
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, NewVerdictData(Verdict{Code: VC(linux.NF_DROP)})),
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NF_DROP)})),
},
{
tname: "verdict register with continue verdict",
opStr: "[ immediate reg 0 continue ]",
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, NewVerdictData(Verdict{Code: VC(linux.NFT_CONTINUE)})),
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NFT_CONTINUE)})),
},
{
tname: "verdict register with return verdict",
opStr: "[ immediate reg 0 return ]",
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, NewVerdictData(Verdict{Code: VC(linux.NFT_RETURN)})),
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NFT_RETURN)})),
},
{
tname: "verdict register with jump verdict",
opStr: "[ immediate reg 0 jump -> next_chain ]",
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, NewVerdictData(Verdict{Code: VC(linux.NFT_JUMP), ChainName: "next_chain"})),
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NFT_JUMP), ChainName: "next_chain"})),
},
{
tname: "verdict register with goto verdict",
opStr: "[ immediate reg 0 goto -> next_chain ]",
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, NewVerdictData(Verdict{Code: VC(linux.NFT_GOTO), ChainName: "next_chain"})),
expected: mustCreateImmediate(t, linux.NFT_REG_VERDICT, newVerdictData(Verdict{Code: VC(linux.NFT_GOTO), ChainName: "next_chain"})),
},
{
tname: "verdict register with 4-byte data",
@@ -113,7 +113,7 @@ func TestInterpretImmediateOps(t *testing.T) {
{
tname: "16-byte register with 4-byte data",
opStr: "[ immediate reg 1 0x0201a8c0 ]",
expected: mustCreateImmediate(t, linux.NFT_REG_1, NewBytesData([]byte{0x02, 0x01, 0xa8, 0xc0})),
expected: mustCreateImmediate(t, linux.NFT_REG_1, newBytesData([]byte{0x02, 0x01, 0xa8, 0xc0})),
},
{
tname: "16-byte register with 6-byte data",
@@ -123,17 +123,17 @@ func TestInterpretImmediateOps(t *testing.T) {
{
tname: "16-byte register with 8-byte data",
opStr: "[ immediate reg 2 0xb80d0120 0x00000050 ]",
expected: mustCreateImmediate(t, linux.NFT_REG_2, NewBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x50})),
expected: mustCreateImmediate(t, linux.NFT_REG_2, newBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x50})),
},
{
tname: "16-byte register with 12-byte data",
opStr: "[ immediate reg 3 0xb80d0120 0x00000050 0xb80d0120 ]",
expected: mustCreateImmediate(t, linux.NFT_REG_3, NewBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x50, 0xb8, 0x0d, 0x01, 0x20})),
expected: mustCreateImmediate(t, linux.NFT_REG_3, newBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x50, 0xb8, 0x0d, 0x01, 0x20})),
},
{
tname: "16-byte register with 16-byte data",
opStr: "[ immediate reg 4 0xb80d0120 0x00000000 0x00000000 0x02000000 ]",
expected: mustCreateImmediate(t, linux.NFT_REG_4, NewBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00})),
expected: mustCreateImmediate(t, linux.NFT_REG_4, newBytesData([]byte{0xb8, 0x0d, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00})),
},
{
tname: "16-byte register with uneven bytes data",
@@ -158,7 +158,7 @@ func TestInterpretImmediateOps(t *testing.T) {
{
tname: "4-byte register with 4-byte data",
opStr: "[ immediate reg 10 0x0201a8c0 ]",
expected: mustCreateImmediate(t, linux.NFT_REG32_02, NewBytesData([]byte{0x02, 0x01, 0xa8, 0xc0})),
expected: mustCreateImmediate(t, linux.NFT_REG32_02, newBytesData([]byte{0x02, 0x01, 0xa8, 0xc0})),
},
{
tname: "4-byte register with 16-byte data",
@@ -172,16 +172,16 @@ func TestInterpretImmediateOps(t *testing.T) {
// checkImmediateOp checks that the given operation is an immediate operation
// and that it matches the expected immediate operation.
func checkImmediateOp(tname string, expected Operation, actual Operation) error {
expectedImm := expected.(*Immediate)
imm, ok := actual.(*Immediate)
func checkImmediateOp(tname string, expected operation, actual operation) error {
expectedImm := expected.(*immediate)
imm, ok := actual.(*immediate)
if !ok {
return fmt.Errorf("expected operation type to be Immediate for %s, got %T", tname, actual)
}
if imm.dreg != expectedImm.dreg {
return fmt.Errorf("expected register to be %d for %s, got %d", expectedImm.dreg, tname, imm.dreg)
}
if !imm.data.Equal(expectedImm.data) {
if !imm.data.equal(expectedImm.data) {
return fmt.Errorf("expected data to be %v for %s, got %v", expectedImm.data, tname, imm.data)
}
return nil
@@ -213,32 +213,32 @@ func TestInterpretComparisonOps(t *testing.T) {
{
tname: "4-byte register == 4-byte data",
opStr: "[ cmp eq reg 8 0x0302010a ]",
expected: mustCreateComparison(t, linux.NFT_REG32_00, linux.NFT_CMP_EQ, NewBytesData([]byte{0x03, 0x02, 0x01, 0x0a})),
expected: mustCreateComparison(t, linux.NFT_REG32_00, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a})),
},
{
tname: "4-byte register != 4-byte data",
opStr: "[ cmp neq reg 9 0x00000064 ]",
expected: mustCreateComparison(t, linux.NFT_REG32_01, linux.NFT_CMP_NEQ, NewBytesData([]byte{0x00, 0x00, 0x00, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG32_01, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64})),
},
{
tname: "4-byte register < 4-byte data",
opStr: "[ cmp lt reg 10 0x00000000 ]",
expected: mustCreateComparison(t, linux.NFT_REG32_02, linux.NFT_CMP_LT, NewBytesData([]byte{0x00, 0x00, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG32_02, linux.NFT_CMP_LT, newBytesData([]byte{0x00, 0x00, 0x00, 0x00})),
},
{
tname: "4-byte register <= 4-byte data",
opStr: "[ cmp lte reg 11 0x00000164 ]",
expected: mustCreateComparison(t, linux.NFT_REG32_03, linux.NFT_CMP_LTE, NewBytesData([]byte{0x00, 0x00, 0x01, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG32_03, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64})),
},
{
tname: "4-byte register > 4-byte data",
opStr: "[ cmp gt reg 12 0xe8030000 ]",
expected: mustCreateComparison(t, linux.NFT_REG32_04, linux.NFT_CMP_GT, NewBytesData([]byte{0xe8, 0x03, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG32_04, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00})),
},
{
tname: "4-byte register >= 4-byte data",
opStr: "[ cmp gte reg 13 0xc02b0000 ]",
expected: mustCreateComparison(t, linux.NFT_REG32_05, linux.NFT_CMP_GTE, NewBytesData([]byte{0xc0, 0x2b, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG32_05, linux.NFT_CMP_GTE, newBytesData([]byte{0xc0, 0x2b, 0x00, 0x00})),
},
{
tname: "4-byte register with 8-byte data comparison",
@@ -258,122 +258,122 @@ func TestInterpretComparisonOps(t *testing.T) {
{
tname: "16-byte register == 4-byte data",
opStr: "[ cmp eq reg 1 0x0302010a ]",
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, NewBytesData([]byte{0x03, 0x02, 0x01, 0x0a})),
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a})),
},
{
tname: "16-byte register != 4-byte data",
opStr: "[ cmp neq reg 2 0x00000064 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, NewBytesData([]byte{0x00, 0x00, 0x00, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64})),
},
{
tname: "16-byte register < 4-byte data",
opStr: "[ cmp lt reg 3 0x00000000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, NewBytesData([]byte{0x00, 0x00, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, newBytesData([]byte{0x00, 0x00, 0x00, 0x00})),
},
{
tname: "16-byte register <= 4-byte data",
opStr: "[ cmp lte reg 4 0x00000164 ]",
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, NewBytesData([]byte{0x00, 0x00, 0x01, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64})),
},
{
tname: "16-byte register > 4-byte data",
opStr: "[ cmp gt reg 1 0xe8030000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_GT, NewBytesData([]byte{0xe8, 0x03, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00})),
},
{
tname: "16-byte register >= 4-byte data",
opStr: "[ cmp gte reg 2 0xc02b0000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GTE, NewBytesData([]byte{0xc0, 0x2b, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GTE, newBytesData([]byte{0xc0, 0x2b, 0x00, 0x00})),
},
{
tname: "16-byte register == 8-byte data",
opStr: "[ cmp eq reg 1 0x0302010a 0x12345678 ]",
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, NewBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x12, 0x34, 0x56, 0x78})),
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x12, 0x34, 0x56, 0x78})),
},
{
tname: "16-byte register != 8-byte data",
opStr: "[ cmp neq reg 2 0x00000064 0x00000020 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, NewBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x20})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x20})),
},
{
tname: "16-byte register < 8-byte data",
opStr: "[ cmp lt reg 3 0x00000000 0x00000000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, NewBytesData([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, newBytesData([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
},
{
tname: "16-byte register <= 8-byte data",
opStr: "[ cmp lte reg 4 0x00000164 0x00000164 ]",
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, NewBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})),
},
{
tname: "16-byte register > 8-byte data",
opStr: "[ cmp gt reg 2 0xe8030000 0x00000f13 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, NewBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13})),
},
{
tname: "16-byte register >= 8-byte data",
opStr: "[ cmp gte reg 3 0x0a000120 0xc0090000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, NewBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0xc0, 0x09, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0xc0, 0x09, 0x00, 0x00})),
},
{
tname: "16-byte register == 12-byte data",
opStr: "[ cmp eq reg 1 0x0302010a 0x00000000 0x12345678 ]",
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, NewBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78})),
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78})),
},
{
tname: "16-byte register != 12-byte data",
opStr: "[ cmp neq reg 2 0x00000064 0x00000000 0x00000020 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, NewBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20})),
},
{
tname: "16-byte register < 12-byte data",
opStr: "[ cmp lt reg 3 0x00000000 0x00000000 0x00000000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, NewBytesData([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, newBytesData([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
},
{
tname: "16-byte register <= 12-byte data",
opStr: "[ cmp lte reg 4 0x00000164 0x00000164 0x00000164 ]",
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, NewBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})),
},
{
tname: "16-byte register > 12-byte data",
opStr: "[ cmp gt reg 2 0xe8030000 0x00000f13 0xc0090000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, NewBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00})),
},
{
tname: "16-byte register >= 12-byte data",
opStr: "[ cmp gte reg 3 0x0a000120 0x00000f13 0xc0090000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, NewBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00})),
},
{
tname: "16-byte register == 16-byte data",
opStr: "[ cmp eq reg 1 0x0302010a 0x00000000 0x00000000 0x02000002 ]",
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, NewBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02})),
expected: mustCreateComparison(t, linux.NFT_REG_1, linux.NFT_CMP_EQ, newBytesData([]byte{0x03, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02})),
},
{
tname: "16-byte register != 16-byte data",
opStr: "[ cmp neq reg 2 0x00000064 0x00000000 0x00000000 0x02000000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, NewBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_NEQ, newBytesData([]byte{0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00})),
},
{
tname: "16-byte register < 16-byte data",
opStr: "[ cmp lt reg 3 0x00000000 0x00000000 0x00000000 0x00000000 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, NewBytesData([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_LT, newBytesData([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})),
},
{
tname: "16-byte register <= 16-byte data",
opStr: "[ cmp lte reg 4 0x00000164 0x00000164 0x00000164 0x00000164 ]",
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, NewBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})),
expected: mustCreateComparison(t, linux.NFT_REG_4, linux.NFT_CMP_LTE, newBytesData([]byte{0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64, 0x00, 0x00, 0x01, 0x64})),
},
{
tname: "16-byte register > 16-byte data",
opStr: "[ cmp gt reg 2 0xe8030000 0x00000f13 0xc0090000 0x0b136a87 ]",
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, NewBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00, 0x0b, 0x13, 0x6a, 0x87})),
expected: mustCreateComparison(t, linux.NFT_REG_2, linux.NFT_CMP_GT, newBytesData([]byte{0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00, 0x0b, 0x13, 0x6a, 0x87})),
},
{
tname: "16-byte register >= 16-byte data",
opStr: "[ cmp gte reg 3 0x0a000120 0x00000f13 0xc0090000 0x0b136a87 ]",
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, NewBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00, 0x0b, 0x13, 0x6a, 0x87})),
expected: mustCreateComparison(t, linux.NFT_REG_3, linux.NFT_CMP_GTE, newBytesData([]byte{0x0a, 0x00, 0x01, 0x20, 0x00, 0x00, 0x0f, 0x13, 0xc0, 0x09, 0x00, 0x00, 0x0b, 0x13, 0x6a, 0x87})),
},
} {
t.Run(test.tname, func(t *testing.T) { checkOp(t, test, checkComparisonOp) })
@@ -382,9 +382,9 @@ func TestInterpretComparisonOps(t *testing.T) {
// checkComparisonOp checks that the given operation is an comparison operation
// and that it matches the expected comparison operation.
func checkComparisonOp(tname string, expected Operation, actual Operation) error {
expectedCmp := expected.(*Comparison)
cmp, ok := actual.(*Comparison)
func checkComparisonOp(tname string, expected operation, actual operation) error {
expectedCmp := expected.(*comparison)
cmp, ok := actual.(*comparison)
if !ok {
return fmt.Errorf("expected operation type to be Comparison for %s, got %T", tname, actual)
}
@@ -394,7 +394,7 @@ func checkComparisonOp(tname string, expected Operation, actual Operation) error
if cmp.cop != expectedCmp.cop {
return fmt.Errorf("expected comparison operator to be %v for %s, got %v", expectedCmp.cop, tname, cmp.cop)
}
if !cmp.data.Equal(expectedCmp.data) {
if !cmp.data.equal(expectedCmp.data) {
return fmt.Errorf("expected data to be %v for %s, got %v", expectedCmp.data, tname, cmp.data)
}
return nil
@@ -442,11 +442,11 @@ func TestInterpretRule(t *testing.T) {
for i, op := range rule.ops {
testOp := test.expected.ops[i]
switch testOp.(type) {
case *Immediate:
case *immediate:
if err := checkImmediateOp(test.tname, testOp, op); err != nil {
t.Fatalf(err.Error())
}
case *Comparison:
case *comparison:
if err := checkComparisonOp(test.tname, testOp, op); err != nil {
t.Fatalf(err.Error())
}