Skip to content

Commit

Permalink
Support Antrea NetworkPolicy in Traceflow (#1361)
Browse files Browse the repository at this point in the history
  • Loading branch information
gran-vmv committed Nov 11, 2020
1 parent 17333f8 commit 6c1a913
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 18 deletions.
57 changes: 44 additions & 13 deletions pkg/agent/controller/traceflow/packetin.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*opsv1alpha1.Tracefl
if err != nil {
return nil, nil, err
}
ob := new(opsv1alpha1.Observation)
ob.Component = opsv1alpha1.NetworkPolicy
ob.ComponentInfo = openflow.GetFlowTableName(openflow.EgressRuleTable)
ob.Action = opsv1alpha1.Forwarded
ob := getNetworkPolicyObservation(tableID, false)
npRef := c.networkPolicyQuerier.GetNetworkPolicyByRuleFlowID(egressInfo)
if npRef != nil {
ob.NetworkPolicy = npRef.ToString()
Expand All @@ -150,10 +147,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*opsv1alpha1.Tracefl
if err != nil {
return nil, nil, err
}
ob := new(opsv1alpha1.Observation)
ob.Component = opsv1alpha1.NetworkPolicy
ob.ComponentInfo = openflow.GetFlowTableName(openflow.IngressRuleTable)
ob.Action = opsv1alpha1.Forwarded
ob := getNetworkPolicyObservation(tableID, true)
npRef := c.networkPolicyQuerier.GetNetworkPolicyByRuleFlowID(ingressInfo)
if npRef != nil {
ob.NetworkPolicy = npRef.ToString()
Expand All @@ -162,11 +156,21 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*opsv1alpha1.Tracefl
}

// Get drop table.
if tableID == uint8(openflow.EgressDefaultTable) || tableID == uint8(openflow.IngressDefaultTable) {
ob := new(opsv1alpha1.Observation)
ob.Action = opsv1alpha1.Dropped
ob.Component = opsv1alpha1.NetworkPolicy
ob.ComponentInfo = openflow.GetFlowTableName(binding.TableIDType(tableID))
if tableID == uint8(openflow.EgressMetricTable) || tableID == uint8(openflow.IngressMetricTable) {
ob := getNetworkPolicyObservation(tableID, tableID == uint8(openflow.IngressMetricTable))
if match = getMatchRegField(matchers, uint32(openflow.CNPDropConjunctionIDReg)); match != nil {
dropConjInfo, err := getInfoInReg(match, nil)
if err != nil {
return nil, nil, err
}
npRef := c.networkPolicyQuerier.GetNetworkPolicyByRuleFlowID(dropConjInfo)
if npRef != nil {
ob.NetworkPolicy = npRef.ToString()
}
}
obs = append(obs, *ob)
} else if tableID == uint8(openflow.EgressDefaultTable) || tableID == uint8(openflow.IngressDefaultTable) {
ob := getNetworkPolicyObservation(tableID, tableID == uint8(openflow.IngressDefaultTable))
obs = append(obs, *ob)
}

Expand Down Expand Up @@ -243,3 +247,30 @@ func getInfoInCtNwDstField(matchers *ofctrl.Matchers) (string, error) {
}
return regValue.String(), nil
}

func getNetworkPolicyObservation(tableID uint8, ingress bool) *opsv1alpha1.Observation {
ob := new(opsv1alpha1.Observation)
ob.Component = opsv1alpha1.NetworkPolicy
if ingress {
switch tableID {
case uint8(openflow.IngressMetricTable), uint8(openflow.IngressDefaultTable):
// Packet dropped by ANP/default drop rule
ob.ComponentInfo = openflow.GetFlowTableName(binding.TableIDType(tableID))
ob.Action = opsv1alpha1.Dropped
default:
ob.ComponentInfo = openflow.GetFlowTableName(openflow.IngressRuleTable)
ob.Action = opsv1alpha1.Forwarded
}
} else {
switch tableID {
case uint8(openflow.EgressMetricTable), uint8(openflow.EgressDefaultTable):
// Packet dropped by ANP/default drop rule
ob.ComponentInfo = openflow.GetFlowTableName(binding.TableIDType(tableID))
ob.Action = opsv1alpha1.Dropped
default:
ob.ComponentInfo = openflow.GetFlowTableName(openflow.EgressRuleTable)
ob.Action = opsv1alpha1.Forwarded
}
}
return ob
}
91 changes: 91 additions & 0 deletions pkg/agent/controller/traceflow/packetin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2020 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package traceflow

import (
"reflect"
"testing"

"github.com/vmware-tanzu/antrea/pkg/agent/openflow"
opsv1alpha1 "github.com/vmware-tanzu/antrea/pkg/apis/ops/v1alpha1"
)

func Test_getNetworkPolicyObservation(t *testing.T) {
type args struct {
tableID uint8
ingress bool
}
tests := []struct {
name string
args args
want *opsv1alpha1.Observation
}{
{
name: "ingress metric drop",
args: args{
tableID: uint8(openflow.IngressMetricTable),
ingress: true,
},
want: &opsv1alpha1.Observation{
Component: opsv1alpha1.NetworkPolicy,
ComponentInfo: "IngressMetric",
Action: opsv1alpha1.Dropped,
},
},
{
name: "ingress accept",
args: args{
tableID: uint8(openflow.L2ForwardingOutTable),
ingress: true,
},
want: &opsv1alpha1.Observation{
Component: opsv1alpha1.NetworkPolicy,
ComponentInfo: "IngressRule",
Action: opsv1alpha1.Forwarded,
},
},
{
name: "egress default drop",
args: args{
tableID: uint8(openflow.EgressDefaultTable),
ingress: false,
},
want: &opsv1alpha1.Observation{
Component: opsv1alpha1.NetworkPolicy,
ComponentInfo: "EgressDefaultRule",
Action: opsv1alpha1.Dropped,
},
},
{
name: "egress accept",
args: args{
tableID: uint8(openflow.L2ForwardingOutTable),
ingress: false,
},
want: &opsv1alpha1.Observation{
Component: opsv1alpha1.NetworkPolicy,
ComponentInfo: "EgressRule",
Action: opsv1alpha1.Forwarded,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getNetworkPolicyObservation(tt.args.tableID, tt.args.ingress); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getNetworkPolicyObservation() = %v, want %v", got, tt.want)
}
})
}
}
16 changes: 15 additions & 1 deletion pkg/agent/openflow/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ func (c *client) InstallTraceflowFlows(dataplaneTag uint8) error {
}
c.conjMatchFlowLock.Lock()
defer c.conjMatchFlowLock.Unlock()
flows = []binding.Flow{}
// Copy default drop rules
for _, ctx := range c.globalConjMatchFlowCache {
if ctx.dropFlow != nil {
flows = append(
Expand All @@ -747,6 +747,20 @@ func (c *client) InstallTraceflowFlows(dataplaneTag uint8) error {
Done())
}
}
// Copy Antrea NetworkPolicy drop rules
for _, conj := range c.policyCache.List() {
for _, flow := range conj.(*policyRuleConjunction).metricFlows {
if flow.IsDropFlow() {
flows = append(
flows,
flow.CopyToBuilder(priorityNormal+2, false).
MatchIPDscp(dataplaneTag).
SetHardTimeout(300).
Action().SendToController(1).
Done())
}
}
}
return c.AddAll(flows)
}

Expand Down
55 changes: 55 additions & 0 deletions pkg/agent/openflow/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"
"time"

"github.com/contiv/ofnet/ofctrl"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -31,6 +32,7 @@ import (
"github.com/vmware-tanzu/antrea/pkg/agent/openflow/cookie"
oftest "github.com/vmware-tanzu/antrea/pkg/agent/openflow/testing"
ofconfig "github.com/vmware-tanzu/antrea/pkg/ovs/openflow"
ovsoftest "github.com/vmware-tanzu/antrea/pkg/ovs/openflow/testing"
"github.com/vmware-tanzu/antrea/pkg/ovs/ovsconfig"
)

Expand Down Expand Up @@ -237,3 +239,56 @@ func TestConcurrentFlowInstallation(t *testing.T) {
}

}

func Test_client_InstallTraceflowFlows(t *testing.T) {
type ofSwitch struct {
ofctrl.OFSwitch
}
type fields struct {
}
type args struct {
dataplaneTag uint8
}
tests := []struct {
name string
fields fields
args args
wantErr bool
prepareFunc func(*gomock.Controller) *client
}{
{
name: "traceflow flow",
fields: fields{},
args: args{dataplaneTag: 1},
wantErr: false,
prepareFunc: prepareTraceflowFlow,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
c := tt.prepareFunc(ctrl)
if err := c.InstallTraceflowFlows(tt.args.dataplaneTag); (err != nil) != tt.wantErr {
t.Errorf("InstallTraceflowFlows() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func prepareTraceflowFlow(ctrl *gomock.Controller) *client {
ofClient := NewClient(bridgeName, bridgeMgmtAddr, true, true)
c := ofClient.(*client)
c.cookieAllocator = cookie.NewAllocator(0)
c.nodeConfig = &config.NodeConfig{}
m := ovsoftest.NewMockBridge(ctrl)
m.EXPECT().AddFlowsInBundle(gomock.Any(), nil, nil).Return(nil).Times(3)
c.bridge = m

mFlow := ovsoftest.NewMockFlow(ctrl)
ctx := &conjMatchFlowContext{dropFlow: mFlow}
mFlow.EXPECT().CopyToBuilder(priorityNormal+2, false).Return(c.pipeline[EgressDefaultTable].BuildFlow(priorityNormal + 2)).Times(1)
c.globalConjMatchFlowCache["mockContext"] = ctx
c.policyCache.Add(&policyRuleConjunction{metricFlows: []ofconfig.Flow{c.dropRuleMetricFlow(123, false)}})
return c
}
1 change: 1 addition & 0 deletions pkg/ovs/openflow/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ type Flow interface {
// It copies the original actions of the Flow only if copyActions is set to true, and
// resets the priority in the new FlowBuilder if the provided priority is not 0.
CopyToBuilder(priority uint16, copyActions bool) FlowBuilder
IsDropFlow() bool
}

type Action interface {
Expand Down
11 changes: 7 additions & 4 deletions pkg/ovs/openflow/ofctrl_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type ofFlowAction struct {
// Drop is an action to drop packets.
func (a *ofFlowAction) Drop() FlowBuilder {
a.builder.Drop()
a.builder.isDropFlow = true
return a.builder
}

Expand Down Expand Up @@ -318,11 +319,13 @@ func (a *ofFlowAction) Note(notes string) FlowBuilder {
}

func (a *ofFlowAction) SendToController(reason uint8) FlowBuilder {
controllerAct := &ofctrl.NXController{
ControllerID: a.builder.ofFlow.Table.Switch.GetControllerID(),
Reason: reason,
if a.builder.ofFlow.Table != nil && a.builder.ofFlow.Table.Switch != nil {
controllerAct := &ofctrl.NXController{
ControllerID: a.builder.ofFlow.Table.Switch.GetControllerID(),
Reason: reason,
}
a.builder.ApplyAction(controllerAct)
}
a.builder.ApplyAction(controllerAct)
return a.builder
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/ovs/openflow/ofctrl_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ type ofFlow struct {
// ctStates is a temporary variable to maintain openflow13.CTStates. When FlowBuilder.Done is called, it is used to
// set the CtStates field in ofctrl.Flow.Match.
ctStates *openflow13.CTStates
// isDropFlow is true if this flow actions contain "drop"
isDropFlow bool
}

// Reset updates the ofFlow.Flow.Table field with ofFlow.table.Table.
Expand Down Expand Up @@ -134,9 +136,16 @@ func (f *ofFlow) CopyToBuilder(priority uint16, copyActions bool) FlowBuilder {
matchers: f.matchers,
protocol: f.protocol,
}
if copyActions {
newFlow.isDropFlow = f.isDropFlow
}
return &ofFlowBuilder{newFlow}
}

func (f *ofFlow) IsDropFlow() bool {
return f.isDropFlow
}

func (r *Range) ToNXRange() *openflow13.NXRange {
return openflow13.NewNXRange(int(r[0]), int(r[1]))
}
Expand Down
21 changes: 21 additions & 0 deletions pkg/ovs/openflow/ofctrl_flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,24 @@ func TestCopyToBuilder(t *testing.T) {
newFlow2 := oriFlow.CopyToBuilder(newPriority, false)
assert.Equal(t, newPriority, newFlow2.Done().(*ofFlow).Match.Priority)
}

func TestCopyToBuilder_Drop(t *testing.T) {
table := &ofTable{
id: 0,
next: 1,
}
oriFlow := table.BuildFlow(uint16(100)).MatchProtocol(ProtocolIP).
Cookie(uint64(1004)).
MatchRegRange(1, 0x101, Range{0, 15}).
MatchCTStateNew(true).MatchCTStateTrk(true).
Action().Drop().
Done()
newFlow := oriFlow.CopyToBuilder(0, false)
assert.Equal(t, oriFlow.MatchString(), newFlow.Done().MatchString())
assert.Equal(t, oriFlow.(*ofFlow).Match, newFlow.Done().(*ofFlow).Match)
assert.Equal(t, false, newFlow.Done().IsDropFlow())
newPriority := uint16(200)
newFlow2 := oriFlow.CopyToBuilder(newPriority, true)
assert.Equal(t, newPriority, newFlow2.Done().(*ofFlow).Match.Priority)
assert.Equal(t, true, newFlow2.Done().IsDropFlow())
}
14 changes: 14 additions & 0 deletions pkg/ovs/openflow/testing/mock_openflow.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6c1a913

Please sign in to comment.