Skip to content

Commit

Permalink
Support AntreaNetworkPolicy reject action in Traceflow
Browse files Browse the repository at this point in the history
  • Loading branch information
gran-vmv committed Apr 6, 2021
1 parent 5752f96 commit 0be85b0
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 37 deletions.
69 changes: 36 additions & 33 deletions pkg/agent/controller/traceflow/packetin.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/vmware-tanzu/antrea/pkg/agent/openflow"
crdv1alpha1 "github.com/vmware-tanzu/antrea/pkg/apis/crd/v1alpha1"
binding "github.com/vmware-tanzu/antrea/pkg/ovs/openflow"
"github.com/vmware-tanzu/antrea/pkg/util/ip"
)

func (c *Controller) HandlePacketIn(pktIn *ofctrl.PacketIn) error {
Expand Down Expand Up @@ -69,23 +70,36 @@ func (c *Controller) HandlePacketIn(pktIn *ofctrl.PacketIn) error {

func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Traceflow, *crdv1alpha1.NodeResult, error) {
matchers := pktIn.GetMatches()
var match *ofctrl.MatchField

// Get data plane tag.
// Directly read data plane tag from packet.
var tag uint8
var err error
var tag, prot uint8
var ctNwDst, ipDst string
if pktIn.Data.Ethertype == protocol.IPv4_MSG {
ipPacket, ok := pktIn.Data.Data.(*protocol.IPv4)
if !ok {
return nil, nil, errors.New("invalid traceflow IPv4 packet")
}
tag = ipPacket.DSCP
prot = ipPacket.Protocol
ctNwDst, err = getCTDstValue(matchers, false)
if err != nil {
return nil, nil, err
}
ipDst = ipPacket.NWDst.String()
} else if pktIn.Data.Ethertype == protocol.IPv6_MSG {
ipv6Packet, ok := pktIn.Data.Data.(*protocol.IPv6)
if !ok {
return nil, nil, errors.New("invalid traceflow IPv6 packet")
}
tag = ipv6Packet.TrafficClass >> 2
prot = ipv6Packet.NextHeader
ctNwDst, err = getCTDstValue(matchers, true)
if err != nil {
return nil, nil, err
}
ipDst = ipv6Packet.NWDst.String()
} else {
return nil, nil, fmt.Errorf("unsupported traceflow packet Ethertype: %d", pktIn.Data.Ethertype)
}
Expand Down Expand Up @@ -129,32 +143,6 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl
}

// Collect Service DNAT.
ctNwDst := ""
ipDst := ""
switch pktIn.Data.Ethertype {
case protocol.IPv4_MSG:
ipPacket, ok := pktIn.Data.Data.(*protocol.IPv4)
if !ok {
return nil, nil, errors.New("invalid traceflow IPv4 packet")
}
ctNwDst, err = getCTDstValue(matchers, false)
if err != nil {
return nil, nil, err
}
ipDst = ipPacket.NWDst.String()
case protocol.IPv6_MSG:
ipPacket, ok := pktIn.Data.Data.(*protocol.IPv6)
if !ok {
return nil, nil, errors.New("invalid traceflow IPv6 packet")
}
ctNwDst, err = getCTDstValue(matchers, true)
if err != nil {
return nil, nil, err
}
ipDst = ipPacket.NWDst.String()
default:
return nil, nil, fmt.Errorf("unsupported traceflow packet ether type %d", pktIn.Data.Ethertype)
}
if isValidCtNw(ctNwDst) && ipDst != ctNwDst {
ob := &crdv1alpha1.Observation{
Component: crdv1alpha1.ComponentLB,
Expand All @@ -165,7 +153,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl
}

// Collect egress conjunctionID and get NetworkPolicy from cache.
if match = getMatchRegField(matchers, uint32(openflow.EgressReg)); match != nil {
if match := getMatchRegField(matchers, uint32(openflow.EgressReg)); match != nil {
egressInfo, err := getRegValue(match, nil)
if err != nil {
return nil, nil, err
Expand All @@ -179,7 +167,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl
}

// Collect ingress conjunctionID and get NetworkPolicy from cache.
if match = getMatchRegField(matchers, uint32(openflow.IngressReg)); match != nil {
if match := getMatchRegField(matchers, uint32(openflow.IngressReg)); match != nil {
ingressInfo, err := getRegValue(match, nil)
if err != nil {
return nil, nil, err
Expand All @@ -195,7 +183,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl
// Get drop table.
if tableID == uint8(openflow.EgressMetricTable) || tableID == uint8(openflow.IngressMetricTable) {
ob := getNetworkPolicyObservation(tableID, tableID == uint8(openflow.IngressMetricTable))
if match = getMatchRegField(matchers, uint32(openflow.CNPDenyConjIDReg)); match != nil {
if match := getMatchRegField(matchers, uint32(openflow.CNPDenyConjIDReg)); match != nil {
notAllowConjInfo, err := getRegValue(match, nil)
if err != nil {
return nil, nil, err
Expand All @@ -205,6 +193,21 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl
ob.NetworkPolicy = npRef.ToString()
}
}
if match := getMatchRegField(matchers, uint32(openflow.CustomReasonMarkReg)); match != nil {
customReasons, err := getRegValue(match, openflow.CustomReasonMarkRange.ToNXRange())
if err != nil {
return nil, nil, err
}
if customReasons&openflow.CustomReasonReject == openflow.CustomReasonReject {
rejectAction := crdv1alpha1.RejectActionICMPProhibited
if prot == ip.TCPProtocol {
rejectAction = crdv1alpha1.RejectActionTCPReset
} else if pktIn.Data.Ethertype == protocol.IPv6_MSG {
rejectAction = crdv1alpha1.RejectActionICMPv6Prohibited
}
ob.RejectAction = &rejectAction
}
}
obs = append(obs, *ob)
} else if tableID == uint8(openflow.EgressDefaultTable) || tableID == uint8(openflow.IngressDefaultTable) {
ob := getNetworkPolicyObservation(tableID, tableID == uint8(openflow.IngressDefaultTable))
Expand All @@ -216,14 +219,14 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl
ob := new(crdv1alpha1.Observation)
tunnelDstIP := ""
isIPv6 := c.nodeConfig.NodeIPAddr.IP.To4() == nil
if match = getMatchTunnelDstField(matchers, isIPv6); match != nil {
if match := getMatchTunnelDstField(matchers, isIPv6); match != nil {
tunnelDstIP, err = getTunnelDstValue(match)
if err != nil {
return nil, nil, err
}
}
var outputPort uint32
if match = getMatchRegField(matchers, uint32(openflow.PortCacheReg)); match != nil {
if match := getMatchRegField(matchers, uint32(openflow.PortCacheReg)); match != nil {
outputPort, err = getRegValue(match, nil)
if err != nil {
return nil, nil, err
Expand Down
11 changes: 11 additions & 0 deletions pkg/apis/crd/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ const (
ActionForwardedOutOfOverlay TraceflowAction = "ForwardedOutOfOverlay"
)

type TraceflowRejectAction string

const (
RejectActionUnknown TraceflowRejectAction = "Unknown"
RejectActionICMPProhibited TraceflowRejectAction = "ICMPProhibited"
RejectActionICMPv6Prohibited TraceflowRejectAction = "ICMPv6Prohibited"
RejectActionTCPReset TraceflowRejectAction = "TCPReset"
)

// List the supported protocols and their codes in traceflow.
// According to code in Antrea agent and controller, default protocol is ICMP if protocol is not inputted by users.
const (
Expand Down Expand Up @@ -234,6 +243,8 @@ type Observation struct {
ComponentInfo string `json:"componentInfo,omitempty" yaml:"componentInfo,omitempty"`
// Action is the action to the observation.
Action TraceflowAction `json:"action,omitempty" yaml:"action,omitempty"`
// RejectAction is the reject action to the observation. Only available when Action is ActionDropped.
RejectAction *TraceflowRejectAction `json:"rejectAction,omitempty" yaml:"rejectAction,omitempty"`
// Pod is the combination of Pod name and Pod Namespace.
Pod string `json:"pod,omitempty" yaml:"pod,omitempty"`
// DstMAC is the destination MAC.
Expand Down
9 changes: 8 additions & 1 deletion pkg/apis/crd/v1alpha1/zz_generated.deepcopy.go

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

69 changes: 66 additions & 3 deletions test/e2e/traceflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,35 @@ func TestTraceflowIntraNodeANP(t *testing.T) {
failOnError(err, t)

node1 := nodeName(0)
node1Pods, _, node1CleanupFn := createTestBusyboxPods(t, data, 2, node1)
node1Pods, _, node1CleanupFn := createTestBusyboxPods(t, data, 3, node1)
defer node1CleanupFn()

var denyIngress *secv1alpha1.NetworkPolicy
denyIngressName := "test-anp-deny-ingress"
if denyIngress, err = data.createANPDenyIngress("antrea-e2e", node1Pods[1], denyIngressName); err != nil {
if denyIngress, err = data.createANPDenyIngress("antrea-e2e", node1Pods[1], denyIngressName, false); err != nil {
t.Fatalf("Error when creating Antrea NetworkPolicy: %v", err)
}
defer func() {
if err = data.deleteAntreaNetworkpolicy(denyIngress); err != nil {
t.Errorf("Error when deleting Antrea NetworkPolicy: %v", err)
}
}()
var rejectIngress *secv1alpha1.NetworkPolicy
rejectIngressName := "test-anp-reject-ingress"
if rejectIngress, err = data.createANPDenyIngress("antrea-e2e", node1Pods[2], rejectIngressName, true); err != nil {
t.Fatalf("Error when creating Antrea NetworkPolicy: %v", err)
}
defer func() {
if err = data.deleteAntreaNetworkpolicy(rejectIngress); err != nil {
t.Errorf("Error when deleting Antrea NetworkPolicy: %v", err)
}
}()
antreaPod, err := data.getAntreaPodOnNode(node1)
if err = data.waitForNetworkpolicyRealized(antreaPod, denyIngressName, v1beta2.AntreaNetworkPolicy); err != nil {
t.Fatal(err)
}

rejectActionTCPReset := v1alpha1.RejectActionTCPReset
testcases := []testcase{
{
name: "ANPDenyIngressIPv4",
Expand Down Expand Up @@ -143,6 +154,54 @@ func TestTraceflowIntraNodeANP(t *testing.T) {
},
},
},
{
name: "ANPRejectIngressIPv4",
ipVersion: 4,
tf: &v1alpha1.Traceflow{
ObjectMeta: metav1.ObjectMeta{
Name: randName(fmt.Sprintf("%s-%s-to-%s-%s-", testNamespace, node1Pods[0], testNamespace, node1Pods[2])),
},
Spec: v1alpha1.TraceflowSpec{
Source: v1alpha1.Source{
Namespace: testNamespace,
Pod: node1Pods[0],
},
Destination: v1alpha1.Destination{
Namespace: testNamespace,
Pod: node1Pods[2],
},
Packet: v1alpha1.Packet{
IPHeader: v1alpha1.IPHeader{
Protocol: protocolTCP,
},
TransportHeader: v1alpha1.TransportHeader{
TCP: &v1alpha1.TCPHeader{
DstPort: 80,
Flags: 2,
},
},
},
},
},
expectedPhase: v1alpha1.Succeeded,
expectedResults: []v1alpha1.NodeResult{
{
Node: node1,
Observations: []v1alpha1.Observation{
{
Component: v1alpha1.ComponentSpoofGuard,
Action: v1alpha1.ActionForwarded,
},
{
Component: v1alpha1.ComponentNetworkPolicy,
ComponentInfo: "IngressMetric",
RejectAction: &rejectActionTCPReset,
Action: v1alpha1.ActionDropped,
},
},
},
},
},
{
name: "ANPDenyIngressIPv6",
ipVersion: 6,
Expand Down Expand Up @@ -1728,6 +1787,7 @@ func compareObservations(expected v1alpha1.NodeResult, actual v1alpha1.NodeResul
exObs[i].ComponentInfo != acObs[i].ComponentInfo ||
exObs[i].Pod != acObs[i].Pod ||
exObs[i].TranslatedDstIP != acObs[i].TranslatedDstIP ||
exObs[i].RejectAction != acObs[i].RejectAction ||
exObs[i].Action != acObs[i].Action {
return fmt.Errorf("Observations should be %v, but got %v", exObs, acObs)
}
Expand All @@ -1736,8 +1796,11 @@ func compareObservations(expected v1alpha1.NodeResult, actual v1alpha1.NodeResul
}

// createANPDenyIngress creates an Antrea NetworkPolicy that denies ingress traffic for pods of specific label.
func (data *TestData) createANPDenyIngress(key string, value string, name string) (*secv1alpha1.NetworkPolicy, error) {
func (data *TestData) createANPDenyIngress(key string, value string, name string, isReject bool) (*secv1alpha1.NetworkPolicy, error) {
dropACT := secv1alpha1.RuleActionDrop
if isReject {
dropACT = secv1alpha1.RuleActionReject
}
anp := secv1alpha1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Expand Down

0 comments on commit 0be85b0

Please sign in to comment.