Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L7 Network Flow Export support in Antrea #5218

Merged
merged 2 commits into from
Jan 24, 2024

Conversation

tushartathgur
Copy link
Contributor

@tushartathgur tushartathgur commented Jul 6, 2023

L7 Network flow export enables Layer 7 flow export as we did for the l3/l4 earlier.
This feature enables the user to export L7 protocol information using:

  • Pod or namespace Annotations

Annotation key used is "visibility.antrea.io/l7-export" and the value is the direction for which the flow export is required, which could be (ingress/egress/both).
Based of the annotation or the NP, the fields ("appProtocolName", "httpVals") are populated and exported.

### - Design:

L7FlowExport is to be designed in order to receive all the protected and unprotected flows of Layer7 type and to be exported.
In order to complete this feature, we need the following flows.

  • L7FlowExport using the Annotations.

    • The flows that are not part of the L7 NP, can also be exported using the pods and Namespace annotations.
    • The annotation key used here is "visibility.antrea.io/l7-export".
    • User can annotate pods or namespaces with the annotation key and a value for the traffic flow direction from the following (Ingress/Egress/both).
    • By default, there will not be any L7 Flow information received by the exporter, i.e. none of the pods or namespaces are annotated by default.
    • Based on the annotation, the L7 Listener will receive the pod or namespace event. L7 Listener would use localPodInformers and namespace informers for this task.
    • Once the correct annotation key-value is received, the pod or pods in an annotated namespace would mirror their traffic to Suricata using Traffic control mark flows
    • Suricata will send the traffic flows information of these mirrored traffic. We currently only support HTTP traffic flows and thus these flows will be the only flows from Suricata to the exporter.
    • Exporter will then populate the necessary fields and export them to the exporters.
  1. Deletion of the flows.
  • Similar to install of new Traffic control mark flows. The deletion of the mark flows will also be taken care of based of two scenarios.
  • User removes the annotations.
  • User deletes the pod or namespace. Only the ready pods or ready pods inside an annotated Namespace will have the corresponding traffic flows.
  • Once any of the two scenarios are met. The corresponding Traffic mark flow will be removed.

New Fields to be added in the exporter.

  • appProtocolName: This field will help export only the l7 flows if required. It is used to also take care of future L7 protocols implementations which may require adding new fields and "appProtocolName" to provide the differentiating field for L7 flows from L3/L4 flows.

  • HttpVals: This field is used and should contain all the http fields (in order) corresponding to a network flow. The fields are:
    [Hostname, URL, UserAgent, ContentType, Method, Protocol, Status, ContentLength]

** GO-IPFIX changes are present in vmware/go-ipfix#315

@tushartathgur tushartathgur marked this pull request as draft July 6, 2023 22:05
@tushartathgur tushartathgur force-pushed the L7_visibility branch 3 times, most recently from 98d13da to 6cc14bb Compare July 20, 2023 04:36
@elton-furtado elton-furtado added this to the Antrea v1.14 release milestone Jul 26, 2023
@tushartathgur tushartathgur force-pushed the L7_visibility branch 8 times, most recently from 8a11a69 to b8555a2 Compare August 3, 2023 19:41
@tushartathgur tushartathgur force-pushed the L7_visibility branch 7 times, most recently from 57fb343 to 2799512 Compare August 4, 2023 00:01
pkg/agent/flowexporter/exporter/exporter.go Outdated Show resolved Hide resolved
pkg/agent/flowexporter/exporter/exporter.go Outdated Show resolved Hide resolved
pkg/agent/flowexporter/exporter/exporter.go Outdated Show resolved Hide resolved
pkg/agent/flowexporter/exporter/exporter.go Outdated Show resolved Hide resolved
@tushartathgur tushartathgur force-pushed the L7_visibility branch 6 times, most recently from ad1eb60 to 56919fe Compare August 7, 2023 23:42
@tushartathgur tushartathgur marked this pull request as ready for review August 8, 2023 02:43
@tushartathgur tushartathgur force-pushed the L7_visibility branch 6 times, most recently from bb15a54 to cf33369 Compare January 18, 2024 12:20
Comment on lines +339 to +344
for connKey, conn := range cs.connections {
l7event, ok := l7EventMap[connKey]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the placement of the second part of the comment is strange:

In case the L7 event is received later than the connkey become unavailable in the cs.connection, we will discard that event

When this happens, we never get to this part of the code, because the for loop (for connKey, conn := range cs.connections) only considers connections in the store. So maybe that second sentence should go before the loop?

}
// In case L7 event is received after the last planned export of the TCP connection, add
// the event back to the queue to be exported in next export cycle. In case the L7 event
// is received later than the connkey become unavailable in the cs.connection, we will
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...is received after the connection is removed from the cs.connections store...

@@ -1865,6 +1879,67 @@ func getAndCheckFlowAggregatorMetrics(t *testing.T, data *TestData) error {
return nil
}

func testL7FlowExporterController(t *testing.T, data *TestData, isIPv6 bool) {
skipIfFeatureDisabled(t, features.L7FlowExporter, true, false)
_, serverIPs, cleanupFunc := createAndWaitForPod(t, data, data.createNginxPodOnNode, "l7flowexportertestpodserver", nodeName(0), data.testNamespace, false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: define nodeName := nodeName(0) at the beginning of the function and use this throughout the test case

@antoninbas
Copy link
Contributor

@yuntanghsu could you take one more look at the new e2e test?

@@ -325,3 +336,27 @@ func (cs *ConntrackConnectionStore) deleteConnWithoutLock(connKey flowexporter.C
func (cs *ConntrackConnectionStore) GetPriorityQueue() *priorityqueue.ExpirePriorityQueue {
return cs.connectionStore.expirePriorityQueue
}

func (cs *ConntrackConnectionStore) fillL7EventInfo(l7EventMap map[flowexporter.Tuple]L7ProtocolFields) {
// In case the L7 event is received after the connection is removed from the cs.connections store.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/store./store,

antoninbas
antoninbas previously approved these changes Jan 18, 2024
test/e2e/flowaggregator_test.go Show resolved Hide resolved
test/e2e/flowaggregator_test.go Outdated Show resolved Hide resolved
Comment on lines +1401 to +1408
func checkL7FlowExporterData(t *testing.T, record, appProtocolName string) {
assert.Containsf(t, record, fmt.Sprintf("appProtocolName: %s", appProtocolName), "Record does not have correct Layer 7 protocol Name")
}

func checkL7FlowExporterDataClickHouse(t *testing.T, record *ClickHouseFullRow, appProtocolName string) {
assert.Equal(t, record.AppProtocolName, appProtocolName, "Record does not have correct Layer 7 protocol Name")
assert.NotEmpty(t, record.HttpVals, "Record does not have httpVals")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these two functions? I think they are only used once and the value of appProtocolName is always http?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the two functions are for two different records, one for click house other one for collector

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. But each one of them is used only once. I was thinking maybe it's better to add line#1402 to line#1927 and line#1406-1407 to line#1939

Copy link
Contributor Author

@tushartathgur tushartathgur Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure , we can do that, however, this helps in future when we may support other protocols

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's keep this as it is, this PR has been pending for a while

test/e2e/flowaggregator_test.go Show resolved Hide resolved
test/e2e/flowaggregator_test.go Outdated Show resolved Hide resolved
Comment on lines 1922 to 1924
assert.Contains(record, testFlow1.srcPodName, "Record with srcIP does not have Pod name: %s", testFlow1.srcPodName)
assert.Contains(record, fmt.Sprintf("sourcePodNamespace: %s", data.testNamespace), "Record does not have correct sourcePodNamespace: %s", data.testNamespace)
assert.Contains(record, fmt.Sprintf("sourceNodeName: %s", nodeName), "Record does not have correct sourceNodeName: %s", nodeName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can reuse checkPodAndNodeData
Like, checkPodAndNodeData(t, record, testFlow1.srcPodName, nodeName, "", "", data.testNamespace)

Copy link
Contributor Author

@tushartathgur tushartathgur Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those functions are specific to perftest labels, we may add a general function later!

test/e2e/flowaggregator_test.go Show resolved Hide resolved
test/e2e/flowaggregator_test.go Outdated Show resolved Hide resolved
test/e2e/flowaggregator_test.go Show resolved Hide resolved
L7 Network flow export enables Layer 7 flow export as we did for the l3/l4 earlier.
This feature enables the user to export L7 protocol information using:

- Pod or namespace Annotations

Annotation key used is "visibility.antrea.io/l7-export" and the value is the direction for which the flow export is required, which could be (ingress/egress/both).
Based of the annotation or the NP, the fields ("appProtocolName", "httpVals") are populated and exported.

Signed-off-by: Tushar Tathgur <tathgurt@tathgurtPNQHP.vmware.com>
tnqn
tnqn previously approved these changes Jan 19, 2024
Copy link
Member

@tnqn tnqn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

antoninbas
antoninbas previously approved these changes Jan 19, 2024
@antoninbas
Copy link
Contributor

/test-all

@tnqn
Copy link
Member

tnqn commented Jan 22, 2024

The new e2e test failed

Signed-off-by: Tushar Tathgur <tathgurt@tathgurtPNQHP.vmware.com>
Copy link
Member

@tnqn tnqn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tnqn
Copy link
Member

tnqn commented Jan 23, 2024

/test-all

@tnqn tnqn merged commit f49a4ea into antrea-io:main Jan 24, 2024
46 of 53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet