diff --git a/docs/antrea-l7-network-policy.md b/docs/antrea-l7-network-policy.md index 198a8b5de55..cc09d44bc65 100644 --- a/docs/antrea-l7-network-policy.md +++ b/docs/antrea-l7-network-policy.md @@ -8,6 +8,7 @@ - [Usage](#usage) - [HTTP](#http) - [More examples](#more-examples) + - [Logs](#logs) - [Limitations](#limitations) @@ -200,6 +201,14 @@ spec: - http: {} # automatically dropped, and subsequent rules will not be considered. ``` +### Logs + +Layer 7 traffic that match the NetworkPolicy will be logged in both an event +triggered log file (`/var/log/antrea/networkpolicy/eve.json`) and a single line +based fast log file (`/var/log/antrea/networkpolicy/fast.log`). Currently, +events include `pass` and `deny`. If `enableLogging` is set for the rule, +packets that matches the rule will also be logged in addition to the event. + ## Limitations This feature is currently only supported for Nodes running Linux. diff --git a/docs/antrea-network-policy.md b/docs/antrea-network-policy.md index 1083bf5c852..7f184de34d9 100644 --- a/docs/antrea-network-policy.md +++ b/docs/antrea-network-policy.md @@ -706,7 +706,9 @@ traffic that matches the "DropToThirdParty" egress rule, while the rule "AllowFromFrontend" is not logged. Specifically for drop and reject rules, deduplication is applied to reduce duplicated logs, and duplication buffer length is set to 1 second. If a rule name is not provided, an identifiable -name will be generated for the rule and displayed in the log. +name will be generated for the rule and displayed in the log. For rules in layer +7 NetworkPolicy, packets are logged with action `Redirect` prior to analysis by +the layer 7 engine, more details are available in the corresponding engine logs. The rules are logged in the following format: ```text diff --git a/pkg/agent/controller/networkpolicy/audit_logging.go b/pkg/agent/controller/networkpolicy/audit_logging.go index 51424a91342..e90f48e4fb9 100644 --- a/pkg/agent/controller/networkpolicy/audit_logging.go +++ b/pkg/agent/controller/networkpolicy/audit_logging.go @@ -195,6 +195,16 @@ func getNetworkPolicyInfo(pktIn *ofctrl.PacketIn, c *Controller, ob *logInfo) er } ob.disposition = openflow.DispositionToString[disposition] + // Get traffic control action, if traffic is redirected, disposition log should be overwritten. + match = getMatchRegField(matchers, openflow.TrafficControlActionField) + trafficControl, err := getInfoInReg(match, openflow.TrafficControlActionField.GetRange().ToNXRange()) + if err != nil { + return fmt.Errorf("received error while unloading traffic control action from reg: %v", err) + } + if trafficControl == openflow.TrafficControlRedirect { + ob.disposition = "Redirect" + } + // Set match to corresponding ingress/egress reg according to disposition. match = getMatch(matchers, tableID, disposition) diff --git a/pkg/agent/controller/networkpolicy/audit_logging_test.go b/pkg/agent/controller/networkpolicy/audit_logging_test.go index 5388a725956..73f35d188bc 100644 --- a/pkg/agent/controller/networkpolicy/audit_logging_test.go +++ b/pkg/agent/controller/networkpolicy/audit_logging_test.go @@ -27,12 +27,12 @@ import ( "antrea.io/libOpenflow/openflow15" "antrea.io/ofnet/ofctrl" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "antrea.io/antrea/pkg/agent/openflow" openflowtest "antrea.io/antrea/pkg/agent/openflow/testing" - "antrea.io/antrea/pkg/apis/controlplane/v1beta2" binding "antrea.io/antrea/pkg/ovs/openflow" "antrea.io/antrea/pkg/util/ip" ) @@ -41,6 +41,12 @@ const ( testBufferLength time.Duration = 100 * time.Millisecond ) +var ( + actionAllow = openflow.DispositionToString[openflow.DispositionAllow] + actionDrop = openflow.DispositionToString[openflow.DispositionDrop] + actionRedirect = "Redirect" +) + // mockLogger implements io.Writer. type mockLogger struct { mu sync.Mutex @@ -122,7 +128,7 @@ func newTestAntreaPolicyLogger(bufferLength time.Duration, clock Clock) (*Antrea func newLogInfo(disposition string) (*logInfo, string) { testLogInfo := &logInfo{ - tableName: "AntreaPolicyIngressRule", + tableName: openflow.AntreaPolicyIngressRuleTable.GetName(), npRef: "AntreaNetworkPolicy:default/test", ruleName: "test-rule", ofPriority: "0", @@ -146,7 +152,7 @@ func expectedLogWithCount(msg string, count int) string { func TestAllowPacketLog(t *testing.T) { antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, &realClock{}) - ob, expected := newLogInfo("Allow") + ob, expected := newLogInfo(actionAllow) antreaLogger.LogDedupPacket(ob) actual := <-mockAnpLogger.logged @@ -155,7 +161,7 @@ func TestAllowPacketLog(t *testing.T) { func TestDropPacketLog(t *testing.T) { antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, &realClock{}) - ob, expected := newLogInfo("Drop") + ob, expected := newLogInfo(actionDrop) antreaLogger.LogDedupPacket(ob) actual := <-mockAnpLogger.logged @@ -166,7 +172,7 @@ func TestDropPacketDedupLog(t *testing.T) { clock := NewVirtualClock(time.Now()) defer clock.Stop() antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, clock) - ob, expected := newLogInfo("Drop") + ob, expected := newLogInfo(actionDrop) // Add the additional log info for duplicate packets. expected = expectedLogWithCount(expected, 2) @@ -187,7 +193,7 @@ func TestDropPacketMultiDedupLog(t *testing.T) { clock := NewVirtualClock(time.Now()) defer clock.Stop() antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, clock) - ob, expected := newLogInfo("Drop") + ob, expected := newLogInfo(actionDrop) consumeLog := func() (int, error) { select { @@ -231,33 +237,158 @@ func TestDropPacketMultiDedupLog(t *testing.T) { assert.Equal(t, 1, c2) } +func TestRedirectPacketLog(t *testing.T) { + antreaLogger, mockAnpLogger := newTestAntreaPolicyLogger(testBufferLength, &realClock{}) + ob, expected := newLogInfo(actionRedirect) + + antreaLogger.LogDedupPacket(ob) + actual := <-mockAnpLogger.logged + assert.Contains(t, actual, expected) +} + func TestGetNetworkPolicyInfo(t *testing.T) { - openflow.InitMockTables( - map[*openflow.Table]uint8{ - openflow.AntreaPolicyEgressRuleTable: uint8(5), - openflow.EgressRuleTable: uint8(6), - openflow.EgressDefaultTable: uint8(7), - openflow.AntreaPolicyIngressRuleTable: uint8(12), - openflow.IngressRuleTable: uint8(13), - openflow.IngressDefaultTable: uint8(14), - }) - c := &Controller{ofClient: &openflowtest.MockClient{}} - ob := new(logInfo) - regID := openflow.APDispositionField.GetRegID() - dispositionMatch := openflow15.MatchField{ - Class: openflow15.OXM_CLASS_PACKET_REGS, - Field: uint8(regID / 2), - HasMask: false, - Value: &openflow15.ByteArrayField{Data: []byte{1, 1, 1, 1}}, + prepareMockOFTablesWithCache() + generateMatch := func(regID int, data []byte) openflow15.MatchField { + return openflow15.MatchField{ + Class: openflow15.OXM_CLASS_PACKET_REGS, + Field: uint8(regID / 2), + HasMask: false, + Value: &openflow15.ByteArrayField{Data: data}, + } + } + testANPRef := "AntreaNetworkPolicy:default/test-anp" + testK8sRef := "AntreaNetworkPolicy:default/test-anp" + testPriority, testRule := "61800", "test-rule" + allowDispositionData := []byte{0x11, 0x11, 0x00, 0x11} + dropDispositionData := []byte{0x11, 0x11, 0x08, 0x11} + noTrafficControlData := []byte{0x11, 0x00, 0x11, 0x11} + redirectTrafficControlData := []byte{0x11, 0x80, 0x11, 0x11} + ingressData := []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11} + tests := []struct { + name string + tableID uint8 + expectedCalls func(mockClient *openflowtest.MockClientMockRecorder) + dispositionData []byte + trafficControlData []byte + ob *logInfo + wantOb *logInfo + wantErr error + }{ + { + name: "ANP Allow", + tableID: openflow.AntreaPolicyIngressRuleTable.GetID(), + expectedCalls: func(mockClient *openflowtest.MockClientMockRecorder) { + mockClient.GetPolicyInfoFromConjunction(gomock.Any()).Return( + testANPRef, testPriority, testRule) + }, + dispositionData: allowDispositionData, + trafficControlData: noTrafficControlData, + wantOb: &logInfo{ + tableName: openflow.AntreaPolicyIngressRuleTable.GetName(), + disposition: actionAllow, + npRef: testANPRef, + ofPriority: testPriority, + ruleName: testRule, + }, + }, + { + name: "K8s Allow", + tableID: openflow.IngressRuleTable.GetID(), + expectedCalls: func(mockClient *openflowtest.MockClientMockRecorder) { + mockClient.GetPolicyInfoFromConjunction(gomock.Any()).Return( + testK8sRef, testPriority, "") + }, + dispositionData: allowDispositionData, + trafficControlData: noTrafficControlData, + wantOb: &logInfo{ + tableName: openflow.IngressRuleTable.GetName(), + disposition: actionAllow, + npRef: testK8sRef, + ofPriority: testPriority, + ruleName: "", + }, + }, + { + name: "ANP Drop", + tableID: openflow.AntreaPolicyIngressRuleTable.GetID(), + expectedCalls: func(mockClient *openflowtest.MockClientMockRecorder) { + mockClient.GetPolicyInfoFromConjunction(gomock.Any()).Return( + testANPRef, testPriority, testRule) + }, + dispositionData: dropDispositionData, + trafficControlData: noTrafficControlData, + wantOb: &logInfo{ + tableName: openflow.AntreaPolicyIngressRuleTable.GetName(), + disposition: actionDrop, + npRef: testANPRef, + ofPriority: testPriority, + ruleName: testRule, + }, + }, + { + name: "K8s Drop", + tableID: openflow.IngressDefaultTable.GetID(), + dispositionData: dropDispositionData, + trafficControlData: noTrafficControlData, + wantOb: &logInfo{ + tableName: openflow.IngressDefaultTable.GetName(), + disposition: actionDrop, + npRef: "K8sNetworkPolicy", + ofPriority: "", + ruleName: "", + }, + }, + { + name: "ANP Redirect", + tableID: openflow.AntreaPolicyIngressRuleTable.GetID(), + expectedCalls: func(mockClient *openflowtest.MockClientMockRecorder) { + mockClient.GetPolicyInfoFromConjunction(gomock.Any()).Return( + testANPRef, testPriority, testRule) + }, + dispositionData: allowDispositionData, + trafficControlData: redirectTrafficControlData, + wantOb: &logInfo{ + tableName: openflow.AntreaPolicyIngressRuleTable.GetName(), + disposition: actionRedirect, + npRef: testANPRef, + ofPriority: testPriority, + ruleName: testRule, + }, + }, } - matchers := []openflow15.MatchField{dispositionMatch} - pktIn := &ofctrl.PacketIn{TableId: 17, Match: openflow15.Match{Fields: matchers}} - err := getNetworkPolicyInfo(pktIn, c, ob) - assert.Equal(t, string(v1beta2.K8sNetworkPolicy), ob.npRef) - assert.Equal(t, "", ob.ofPriority) - assert.Equal(t, "", ob.ruleName) - require.NoError(t, err) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Inject disposition match. + dispositionMatch := generateMatch(openflow.APDispositionField.GetRegID(), tc.dispositionData) + matchers := []openflow15.MatchField{dispositionMatch} + // Inject traffic control action match. + trafficControlMatch := generateMatch(openflow.TrafficControlActionField.GetRegID(), tc.trafficControlData) + matchers = append(matchers, trafficControlMatch) + // Inject ingress/egress match when case is not K8s default drop. + if tc.expectedCalls != nil { + regID := openflow.TFIngressConjIDField.GetRegID() + if tc.wantOb.disposition == actionDrop { + regID = openflow.CNPConjIDField.GetRegID() + } + ingressMatch := generateMatch(regID, ingressData) + matchers = append(matchers, ingressMatch) + } + pktIn := &ofctrl.PacketIn{TableId: tc.tableID, Match: openflow15.Match{Fields: matchers}} + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + testClientInterface := openflowtest.NewMockClient(ctrl) + if tc.expectedCalls != nil { + tc.expectedCalls(testClientInterface.EXPECT()) + } + c := &Controller{ofClient: testClientInterface} + tc.ob = new(logInfo) + gotErr := getNetworkPolicyInfo(pktIn, c, tc.ob) + assert.Equal(t, tc.wantOb, tc.ob) + assert.Equal(t, tc.wantErr, gotErr) + }) + } } func TestGetPacketInfo(t *testing.T) { @@ -277,7 +408,6 @@ func TestGetPacketInfo(t *testing.T) { SourcePort: 35402, DestinationPort: 80, }, - ob: new(logInfo), wantOb: &logInfo{ srcIP: "0.0.0.0", srcPort: "35402", @@ -295,7 +425,6 @@ func TestGetPacketInfo(t *testing.T) { IPLength: 60, IPProto: ip.ICMPProtocol, }, - ob: new(logInfo), wantOb: &logInfo{ srcIP: "0.0.0.0", srcPort: "", @@ -308,7 +437,13 @@ func TestGetPacketInfo(t *testing.T) { } for _, tc := range tests { + tc.ob = new(logInfo) getPacketInfo(tc.packet, tc.ob) assert.Equal(t, tc.wantOb, tc.ob) } } + +func prepareMockOFTablesWithCache() { + openflow.InitMockTables(mockOFTables) + openflow.InitOFTableCache(mockOFTables) +} diff --git a/pkg/agent/controller/networkpolicy/l7engine/reconciler.go b/pkg/agent/controller/networkpolicy/l7engine/reconciler.go index 22972064a60..2b6fd64898d 100644 --- a/pkg/agent/controller/networkpolicy/l7engine/reconciler.go +++ b/pkg/agent/controller/networkpolicy/l7engine/reconciler.go @@ -36,6 +36,7 @@ import ( const ( defaultSuricataConfigPath = "/etc/suricata/suricata.yaml" antreaSuricataConfigPath = "/etc/suricata/antrea.yaml" + antreaSuricataLogPath = "/var/log/antrea/networkpolicy/l7engine/" tenantConfigsDir = "/etc/suricata" tenantRulesDir = "/etc/suricata/rules" @@ -104,12 +105,17 @@ func NewReconciler() *Reconciler { } } -func generateTenantRulesData(policyName string, protoKeywords map[string]sets.String) *bytes.Buffer { +func generateTenantRulesData(policyName string, protoKeywords map[string]sets.String, enableLogging bool) *bytes.Buffer { rulesData := bytes.NewBuffer(nil) sid := 1 + var tagKeyword string + if enableLogging { + tagKeyword = " tag: session, 30, seconds;" + } + // Generate default reject rule. - allKeywords := fmt.Sprintf(`msg: "Reject by %s"; flow: to_server, established; sid: %d;`, policyName, sid) + allKeywords := fmt.Sprintf(`msg: "Reject by %s"; flow: to_server, established;%s sid: %d;`, policyName, tagKeyword, sid) rule := fmt.Sprintf("reject ip any any -> any any (%s)\n", allKeywords) rulesData.WriteString(rule) sid++ @@ -120,9 +126,9 @@ func generateTenantRulesData(policyName string, protoKeywords map[string]sets.St // It is a convention that the sid is provided as the last keyword (or second-to-last if there is a rev) // of a rule. if keywords != "" { - allKeywords = fmt.Sprintf(`msg: "Allow %s by %s"; %s sid: %d;`, proto, policyName, keywords, sid) + allKeywords = fmt.Sprintf(`msg: "Allow %s by %s"; %s%s sid: %d;`, proto, policyName, keywords, tagKeyword, sid) } else { - allKeywords = fmt.Sprintf(`msg: "Allow %s by %s"; sid: %d;`, proto, policyName, sid) + allKeywords = fmt.Sprintf(`msg: "Allow %s by %s";%s sid: %d;`, proto, policyName, tagKeyword, sid) } rule = fmt.Sprintf("pass %s any any -> any any (%s)\n", proto, allKeywords) rulesData.WriteString(rule) @@ -187,7 +193,7 @@ func convertProtocolHTTP(http *v1beta.HTTPProtocol) string { return strings.Join(keywords, " ") } -func (r *Reconciler) AddRule(ruleID, policyName string, vlanID uint32, l7Protocols []v1beta.L7Protocol) error { +func (r *Reconciler) AddRule(ruleID, policyName string, vlanID uint32, l7Protocols []v1beta.L7Protocol, enableLogging bool) error { start := time.Now() defer func() { klog.V(5).Infof("AddRule took %v", time.Since(start)) @@ -212,7 +218,7 @@ func (r *Reconciler) AddRule(ruleID, policyName string, vlanID uint32, l7Protoco klog.InfoS("Reconciling L7 rule", "RuleID", ruleID, "PolicyName", policyName) // Write the Suricata rules to file. rulesPath := generateTenantRulesPath(vlanID) - rulesData := generateTenantRulesData(policyName, protoKeywords) + rulesData := generateTenantRulesData(policyName, protoKeywords, enableLogging) if err := writeConfigFile(rulesPath, rulesData); err != nil { return fmt.Errorf("failed to write Suricata rules data to file %s for L7 rule %s of %s", rulesPath, ruleID, policyName) } @@ -383,6 +389,24 @@ func (r *Reconciler) startSuricata() { // /etc/suricata/suricata.yaml. suricataAntreaConfigData := fmt.Sprintf(`%%YAML 1.1 --- +outputs: + - fast: + enabled: yes + filename: fast.log + append: yes + - eve-log: + enabled: yes + filetype: regular + filename: eve-%%Y-%%m-%%d.json + rotate-interval: day + pcap-file: false + community-id: false + community-id-seed: 0 + xff: + enabled: no + types: + - alert: + tagged-packets: yes af-packet: - interface: %[1]s threads: auto @@ -449,8 +473,12 @@ multi-detect: } func startSuricata() { + // Create log directory /var/log/antrea/networkpolicy/l7engine/ for Suricata. + if err := os.Mkdir(antreaSuricataLogPath, os.ModePerm); err != nil { + klog.ErrorS(err, "Failed to create L7 Network Policy log directory", "Directory", antreaSuricataLogPath) + } // Start Suricata with default Suricata config file /etc/suricata/suricata.yaml. - cmd := exec.Command("suricata", "-c", defaultSuricataConfigPath, "--af-packet", "-D") + cmd := exec.Command("suricata", "-c", defaultSuricataConfigPath, "--af-packet", "-D", "-l", antreaSuricataLogPath) if err := cmd.Start(); err != nil { klog.ErrorS(err, "Failed to start Suricata instance") } diff --git a/pkg/agent/controller/networkpolicy/l7engine/reconciler_test.go b/pkg/agent/controller/networkpolicy/l7engine/reconciler_test.go index 2f99afbd9d8..371e777d9d9 100644 --- a/pkg/agent/controller/networkpolicy/l7engine/reconciler_test.go +++ b/pkg/agent/controller/networkpolicy/l7engine/reconciler_test.go @@ -106,6 +106,24 @@ func TestStartSuricata(t *testing.T) { fe.startSuricata() ok, err := afero.FileContainsBytes(defaultFS, antreaSuricataConfigPath, []byte(`--- +outputs: + - fast: + enabled: yes + filename: fast.log + append: yes + - eve-log: + enabled: yes + filetype: regular + filename: eve-%Y-%m-%d.json + rotate-interval: day + pcap-file: false + community-id: false + community-id-seed: 0 + xff: + enabled: no + types: + - alert: + tagged-packets: yes af-packet: - interface: antrea-l7-tap0 threads: auto @@ -187,7 +205,7 @@ func TestRuleLifecycle(t *testing.T) { fe.startSuricataFn = fs.startSuricataFn // Test add a L7 NetworkPolicy. - assert.NoError(t, fe.AddRule(ruleID, policyName, vlanID, tc.l7Protocols)) + assert.NoError(t, fe.AddRule(ruleID, policyName, vlanID, tc.l7Protocols, false)) rulesPath := generateTenantRulesPath(vlanID) ok, err := afero.FileContainsBytes(defaultFS, rulesPath, []byte(tc.expectedRules)) @@ -204,7 +222,7 @@ func TestRuleLifecycle(t *testing.T) { assert.Equal(t, expectedScCommands, fs.calledScCommands) // Update the added L7 NetworkPolicy. - assert.NoError(t, fe.AddRule(ruleID, policyName, vlanID, tc.updatedL7Protocols)) + assert.NoError(t, fe.AddRule(ruleID, policyName, vlanID, tc.updatedL7Protocols, false)) expectedScCommands.Insert("reload-tenant 1 /etc/suricata/antrea-tenant-1.yaml") assert.Equal(t, expectedScCommands, fs.calledScCommands) diff --git a/pkg/agent/controller/networkpolicy/networkpolicy_controller.go b/pkg/agent/controller/networkpolicy/networkpolicy_controller.go index 1ce4415856e..10ac153d8c6 100644 --- a/pkg/agent/controller/networkpolicy/networkpolicy_controller.go +++ b/pkg/agent/controller/networkpolicy/networkpolicy_controller.go @@ -58,7 +58,7 @@ const ( ) type L7RuleReconciler interface { - AddRule(ruleID, policyName string, vlanID uint32, l7Protocols []v1beta2.L7Protocol) error + AddRule(ruleID, policyName string, vlanID uint32, l7Protocols []v1beta2.L7Protocol, enableLogging bool) error DeleteRule(ruleID string, vlanID uint32) error } @@ -642,7 +642,7 @@ func (c *Controller) syncRule(key string) error { vlanID := c.l7VlanIDAllocator.allocate(key) rule.L7RuleVlanID = &vlanID - if err := c.l7RuleReconciler.AddRule(key, rule.SourceRef.ToString(), vlanID, rule.L7Protocols); err != nil { + if err := c.l7RuleReconciler.AddRule(key, rule.SourceRef.ToString(), vlanID, rule.L7Protocols, rule.EnableLogging); err != nil { return err } } @@ -687,7 +687,7 @@ func (c *Controller) syncRules(keys []string) error { vlanID := c.l7VlanIDAllocator.allocate(key) rule.L7RuleVlanID = &vlanID - if err := c.l7RuleReconciler.AddRule(key, rule.SourceRef.ToString(), vlanID, rule.L7Protocols); err != nil { + if err := c.l7RuleReconciler.AddRule(key, rule.SourceRef.ToString(), vlanID, rule.L7Protocols, rule.EnableLogging); err != nil { return err } } diff --git a/pkg/agent/controller/networkpolicy/networkpolicy_controller_test.go b/pkg/agent/controller/networkpolicy/networkpolicy_controller_test.go index cb396d77889..1b2b2af380c 100644 --- a/pkg/agent/controller/networkpolicy/networkpolicy_controller_test.go +++ b/pkg/agent/controller/networkpolicy/networkpolicy_controller_test.go @@ -47,6 +47,15 @@ import ( const testNamespace = "ns1" +var mockOFTables = map[*openflow.Table]uint8{ + openflow.AntreaPolicyEgressRuleTable: uint8(5), + openflow.EgressRuleTable: uint8(6), + openflow.EgressDefaultTable: uint8(7), + openflow.AntreaPolicyIngressRuleTable: uint8(12), + openflow.IngressRuleTable: uint8(13), + openflow.IngressDefaultTable: uint8(14), +} + type antreaClientGetter struct { clientset versioned.Interface } @@ -203,15 +212,7 @@ func newNetworkPolicyWithMultipleRules(name string, uid types.UID, from, to, app } func prepareMockTables() { - openflow.InitMockTables( - map[*openflow.Table]uint8{ - openflow.AntreaPolicyEgressRuleTable: uint8(5), - openflow.EgressRuleTable: uint8(6), - openflow.EgressDefaultTable: uint8(7), - openflow.AntreaPolicyIngressRuleTable: uint8(12), - openflow.IngressRuleTable: uint8(13), - openflow.IngressDefaultTable: uint8(14), - }) + openflow.InitMockTables(mockOFTables) } func TestAddSingleGroupRule(t *testing.T) { diff --git a/pkg/agent/openflow/fields.go b/pkg/agent/openflow/fields.go index 72ddd62b3be..2f60ba56fc6 100644 --- a/pkg/agent/openflow/fields.go +++ b/pkg/agent/openflow/fields.go @@ -126,8 +126,8 @@ var ( ToClusterServiceRegMark = binding.NewOneBitRegMark(4, 21) // reg4[22..23]: Field to store the action of a traffic control rule. Marks in this field include: TrafficControlActionField = binding.NewRegField(4, 22, 23) - TrafficControlMirrorRegMark = binding.NewRegMark(TrafficControlActionField, 0b01) - TrafficControlRedirectRegMark = binding.NewRegMark(TrafficControlActionField, 0b10) + TrafficControlMirrorRegMark = binding.NewRegMark(TrafficControlActionField, TrafficControlMirror) + TrafficControlRedirectRegMark = binding.NewRegMark(TrafficControlActionField, TrafficControlRedirect) // reg5(NXM_NX_REG5) // Field to cache the Egress conjunction ID hit by TraceFlow packet. diff --git a/pkg/agent/openflow/openflow_test_utils.go b/pkg/agent/openflow/openflow_test_utils.go index 59457e26b64..679d6726d43 100644 --- a/pkg/agent/openflow/openflow_test_utils.go +++ b/pkg/agent/openflow/openflow_test_utils.go @@ -25,6 +25,13 @@ func InitMockTables(tableMap map[*Table]uint8) { } } +// InitOFTableCache is used to update ofTableCache in tests. +func InitOFTableCache(tableMap map[*Table]uint8) { + for ft := range tableMap { + tableCache.Update(ft) + } +} + // ResetOFTable is used for integration tests. func ResetOFTable() { binding.ResetTableID() diff --git a/pkg/agent/openflow/pipeline.go b/pkg/agent/openflow/pipeline.go index 15819c410bf..b2460d22e9c 100644 --- a/pkg/agent/openflow/pipeline.go +++ b/pkg/agent/openflow/pipeline.go @@ -363,6 +363,11 @@ const ( CustomReasonDNS = 0b1000 CustomReasonIGMP = 0b10000 + // TrafficControlMirror and TrafficControlRedirect are values used in traffic + // control action field. + TrafficControlMirror = 0b01 + TrafficControlRedirect = 0b10 + // EtherTypeDot1q is used when adding 802.1Q VLAN header in OVS action EtherTypeDot1q = 0x8100 ) @@ -1773,8 +1778,8 @@ func (f *featureNetworkPolicy) conjunctionActionFlow(conjunctionID uint32, table } if l7RuleVlanID != nil { return fb. - Action().LoadToRegField(conjReg, conjunctionID). // Traceflow. - Action().LoadRegMark(DispositionAllowRegMark, CustomReasonLoggingRegMark). // AntreaPolicy, Enable logging. + Action().LoadToRegField(conjReg, conjunctionID). // Traceflow. + Action().LoadRegMark(DispositionAllowRegMark, CustomReasonLoggingRegMark, TrafficControlRedirectRegMark). // AntreaPolicy, Enable logging. Action().SendToController(uint8(PacketInReasonNP)). Action().CT(true, nextTable, ctZone, f.ctZoneSrcField). // CT action requires commit flag if actions other than NAT without arguments are specified. LoadToLabelField(uint64(conjunctionID), labelField).