Local Traffic Detector: Add two new modes

This PR introduces two new modes for detecting
local traffic in a cluster.
1) detectLocalByBridgeInterface: This takes a bridge name
as argument and decides all traffic that match on their
originating interface being that of this bridge, shall be
considered as local pod traffic.
2) detectLocalByInterfaceNamePrefix: This takes an interface prefix
name as argument and decides all traffic that match on their
originating interface names having a prefix that matches this
argument shall be considered as local pod traffic.

Signed-off-by: Surya Seetharaman <suryaseetharaman.9@gmail.com>
This commit is contained in:
Surya Seetharaman 2022-01-29 12:00:37 +01:00
parent e7845861a5
commit 5632991115
2 changed files with 191 additions and 0 deletions

View File

@ -87,3 +87,62 @@ func (d *detectLocalByCIDR) IfLocal() []string {
func (d *detectLocalByCIDR) IfNotLocal() []string {
return d.ifNotLocal
}
type detectLocalByBridgeInterface struct {
ifLocal []string
ifNotLocal []string
}
// NewDetectLocalByBridgeInterface implements the LocalTrafficDetector interface using a bridge interface name.
// This can be used when a bridge can be used to capture the notion of local traffic from pods.
func NewDetectLocalByBridgeInterface(interfaceName string) (LocalTrafficDetector, error) {
if len(interfaceName) == 0 {
return nil, fmt.Errorf("no bridge interface name set")
}
return &detectLocalByBridgeInterface{
ifLocal: []string{"-i", interfaceName},
ifNotLocal: []string{"!", "-i", interfaceName},
}, nil
}
func (d *detectLocalByBridgeInterface) IsImplemented() bool {
return true
}
func (d *detectLocalByBridgeInterface) IfLocal() []string {
return d.ifLocal
}
func (d *detectLocalByBridgeInterface) IfNotLocal() []string {
return d.ifNotLocal
}
type detectLocalByInterfaceNamePrefix struct {
ifLocal []string
ifNotLocal []string
}
// NewDetectLocalByInterfaceNamePrefix implements the LocalTrafficDetector interface using an interface name prefix.
// This can be used when a pod interface name prefix can be used to capture the notion of local traffic. Note
// that this will match on all interfaces that start with the given prefix.
func NewDetectLocalByInterfaceNamePrefix(interfacePrefix string) (LocalTrafficDetector, error) {
if len(interfacePrefix) == 0 {
return nil, fmt.Errorf("no interface prefix set")
}
return &detectLocalByInterfaceNamePrefix{
ifLocal: []string{"-i", interfacePrefix + "+"},
ifNotLocal: []string{"!", "-i", interfacePrefix + "+"},
}, nil
}
func (d *detectLocalByInterfaceNamePrefix) IsImplemented() bool {
return true
}
func (d *detectLocalByInterfaceNamePrefix) IfLocal() []string {
return d.ifLocal
}
func (d *detectLocalByInterfaceNamePrefix) IfNotLocal() []string {
return d.ifNotLocal
}

View File

@ -144,3 +144,135 @@ func TestDetectLocalByCIDR(t *testing.T) {
}
}
}
func TestNewDetectLocalByBridgeInterface(t *testing.T) {
cases := []struct {
ifaceName string
errExpected bool
}{
{
ifaceName: "avz",
errExpected: false,
},
{
ifaceName: "",
errExpected: true,
},
}
for i, c := range cases {
r, err := NewDetectLocalByBridgeInterface(c.ifaceName)
if c.errExpected {
if err == nil {
t.Errorf("Case[%d] expected error, but succeeded with: %q", i, r)
}
continue
}
if err != nil {
t.Errorf("Case[%d] failed with error: %v", i, err)
}
}
}
func TestNewDetectLocalByInterfaceNamePrefix(t *testing.T) {
cases := []struct {
ifacePrefix string
errExpected bool
}{
{
ifacePrefix: "veth",
errExpected: false,
},
{
ifacePrefix: "cbr0",
errExpected: false,
},
{
ifacePrefix: "",
errExpected: true,
},
}
for i, c := range cases {
r, err := NewDetectLocalByInterfaceNamePrefix(c.ifacePrefix)
if c.errExpected {
if err == nil {
t.Errorf("Case[%d] expected error, but succeeded with: %q", i, r)
}
continue
}
if err != nil {
t.Errorf("Case[%d] failed with error: %v", i, err)
}
}
}
func TestDetectLocalByBridgeInterface(t *testing.T) {
cases := []struct {
ifaceName string
expectedJumpIfOutput []string
expectedJumpIfNotOutput []string
}{
{
ifaceName: "eth0",
expectedJumpIfOutput: []string{"-i", "eth0"},
expectedJumpIfNotOutput: []string{"!", "-i", "eth0"},
},
}
for _, c := range cases {
localDetector, err := NewDetectLocalByBridgeInterface(c.ifaceName)
if err != nil {
t.Errorf("Error initializing localDetector: %v", err)
continue
}
if !localDetector.IsImplemented() {
t.Error("DetectLocalByBridgeInterface returns false for IsImplemented")
}
ifLocal := localDetector.IfLocal()
ifNotLocal := localDetector.IfNotLocal()
if !reflect.DeepEqual(ifLocal, c.expectedJumpIfOutput) {
t.Errorf("IfLocal, expected: '%v', but got: '%v'", c.expectedJumpIfOutput, ifLocal)
}
if !reflect.DeepEqual(ifNotLocal, c.expectedJumpIfNotOutput) {
t.Errorf("IfNotLocal, expected: '%v', but got: '%v'", c.expectedJumpIfNotOutput, ifNotLocal)
}
}
}
func TestDetectLocalByInterfaceNamePrefix(t *testing.T) {
cases := []struct {
ifacePrefix string
chain string
args []string
expectedJumpIfOutput []string
expectedJumpIfNotOutput []string
}{
{
ifacePrefix: "eth0",
expectedJumpIfOutput: []string{"-i", "eth0+"},
expectedJumpIfNotOutput: []string{"!", "-i", "eth0+"},
},
}
for _, c := range cases {
localDetector, err := NewDetectLocalByInterfaceNamePrefix(c.ifacePrefix)
if err != nil {
t.Errorf("Error initializing localDetector: %v", err)
continue
}
if !localDetector.IsImplemented() {
t.Error("DetectLocalByInterfaceNamePrefix returns false for IsImplemented")
}
ifLocal := localDetector.IfLocal()
ifNotLocal := localDetector.IfNotLocal()
if !reflect.DeepEqual(ifLocal, c.expectedJumpIfOutput) {
t.Errorf("IfLocal, expected: '%v', but got: '%v'", c.expectedJumpIfOutput, ifLocal)
}
if !reflect.DeepEqual(ifNotLocal, c.expectedJumpIfNotOutput) {
t.Errorf("IfNotLocal, expected: '%v', but got: '%v'", c.expectedJumpIfNotOutput, ifNotLocal)
}
}
}