-
Notifications
You must be signed in to change notification settings - Fork 373
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
Add flowType field for Flow Exporter #2000
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ import ( | |
"github.com/vmware-tanzu/antrea/pkg/agent/route" | ||
"github.com/vmware-tanzu/antrea/pkg/agent/util" | ||
"github.com/vmware-tanzu/antrea/pkg/ovs/ovsconfig" | ||
utilip "github.com/vmware-tanzu/antrea/pkg/util/ip" | ||
) | ||
|
||
const ( | ||
|
@@ -97,7 +98,8 @@ func NewNodeRouteController( | |
nodeLister: nodeInformer.Lister(), | ||
nodeListerSynced: nodeInformer.Informer().HasSynced, | ||
queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(minRetryDelay, maxRetryDelay), "noderoute"), | ||
installedNodes: cache.NewIndexer(nodeRouteInfoKeyFunc, cache.Indexers{nodeRouteInfoPodCIDRIndexName: nodeRouteInfoPodCIDRIndexFunc})} | ||
installedNodes: cache.NewIndexer(nodeRouteInfoKeyFunc, cache.Indexers{nodeRouteInfoPodCIDRIndexName: nodeRouteInfoPodCIDRIndexFunc}), | ||
} | ||
nodeInformer.Informer().AddEventHandlerWithResyncPeriod( | ||
cache.ResourceEventHandlerFuncs{ | ||
AddFunc: func(cur interface{}) { | ||
|
@@ -615,3 +617,39 @@ func GetNodeAddr(node *corev1.Node) (net.IP, error) { | |
} | ||
return ipAddr, nil | ||
} | ||
|
||
func (c *Controller) IPInPodSubnets(ip net.IP) bool { | ||
var ipCIDR *net.IPNet | ||
var curNodeCIDRStr string | ||
if ip.To4() != nil { | ||
var podIPv4CIDRMaskSize int | ||
if c.nodeConfig.PodIPv4CIDR != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we tend to use early returns when possible to reduce indentation levels: if c.nodeConfig.PodIPv4CIDR == nil {
return false
}
curNodeCIDRStr = c.nodeConfig.PodIPv4CIDR.String()
podIPv4CIDRMaskSize, _ := c.nodeConfig.PodIPv4CIDR.Mask.Size() same below this can be addressed in a future PR |
||
curNodeCIDRStr = c.nodeConfig.PodIPv4CIDR.String() | ||
podIPv4CIDRMaskSize, _ = c.nodeConfig.PodIPv4CIDR.Mask.Size() | ||
} else { | ||
return false | ||
} | ||
v4Mask := net.CIDRMask(podIPv4CIDRMaskSize, utilip.V4BitLen) | ||
ipCIDR = &net.IPNet{ | ||
IP: ip.Mask(v4Mask), | ||
Mask: v4Mask, | ||
} | ||
|
||
} else { | ||
var podIPv6CIDRMaskSize int | ||
if c.nodeConfig.PodIPv6CIDR != nil { | ||
curNodeCIDRStr = c.nodeConfig.PodIPv6CIDR.String() | ||
podIPv6CIDRMaskSize, _ = c.nodeConfig.PodIPv6CIDR.Mask.Size() | ||
} else { | ||
return false | ||
} | ||
v6Mask := net.CIDRMask(podIPv6CIDRMaskSize, utilip.V6BitLen) | ||
ipCIDR = &net.IPNet{ | ||
IP: ip.Mask(v6Mask), | ||
Mask: v6Mask, | ||
} | ||
} | ||
ipCIDRStr := ipCIDR.String() | ||
nodeInCluster, _ := c.installedNodes.ByIndex(nodeRouteInfoPodCIDRIndexName, ipCIDRStr) | ||
return len(nodeInCluster) > 0 || ipCIDRStr == curNodeCIDRStr | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,9 +27,11 @@ import ( | |
"k8s.io/client-go/kubernetes" | ||
"k8s.io/klog" | ||
|
||
"github.com/vmware-tanzu/antrea/pkg/agent/controller/noderoute" | ||
"github.com/vmware-tanzu/antrea/pkg/agent/flowexporter" | ||
"github.com/vmware-tanzu/antrea/pkg/agent/flowexporter/connections" | ||
"github.com/vmware-tanzu/antrea/pkg/agent/flowexporter/flowrecords" | ||
"github.com/vmware-tanzu/antrea/pkg/agent/openflow" | ||
"github.com/vmware-tanzu/antrea/pkg/ipfix" | ||
"github.com/vmware-tanzu/antrea/pkg/util/env" | ||
) | ||
|
@@ -94,6 +96,8 @@ type flowExporter struct { | |
idleFlowTimeout time.Duration | ||
enableTLSToFlowAggregator bool | ||
k8sClient kubernetes.Interface | ||
nodeRouteController *noderoute.Controller | ||
isNetworkPolicyOnly bool | ||
} | ||
|
||
func genObservationID() (uint32, error) { | ||
|
@@ -123,7 +127,8 @@ func prepareExporterInputArgs(collectorAddr, collectorProto string) (exporter.Ex | |
|
||
func NewFlowExporter(connStore connections.ConnectionStore, records *flowrecords.FlowRecords, | ||
collectorAddr string, collectorProto string, activeFlowTimeout time.Duration, idleFlowTimeout time.Duration, | ||
enableTLSToFlowAggregator bool, v4Enabled bool, v6Enabled bool, k8sClient kubernetes.Interface) (*flowExporter, error) { | ||
enableTLSToFlowAggregator bool, v4Enabled bool, v6Enabled bool, k8sClient kubernetes.Interface, | ||
nodeRouteController *noderoute.Controller, isNetworkPolicyOnly bool) (*flowExporter, error) { | ||
// Initialize IPFIX registry | ||
registry := ipfix.NewIPFIXRegistry() | ||
registry.LoadRegistry() | ||
|
@@ -133,6 +138,7 @@ func NewFlowExporter(connStore connections.ConnectionStore, records *flowrecords | |
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &flowExporter{ | ||
connStore: connStore, | ||
flowRecords: records, | ||
|
@@ -145,6 +151,8 @@ func NewFlowExporter(connStore connections.ConnectionStore, records *flowrecords | |
ipfixSet: ipfix.NewSet(false), | ||
enableTLSToFlowAggregator: enableTLSToFlowAggregator, | ||
k8sClient: k8sClient, | ||
nodeRouteController: nodeRouteController, | ||
isNetworkPolicyOnly: isNetworkPolicyOnly, | ||
}, nil | ||
} | ||
|
||
|
@@ -516,12 +524,7 @@ func (exp *flowExporter) addRecordToSet(record flowexporter.FlowRecord) error { | |
case "tcpState": | ||
ie.Value = record.Conn.TCPState | ||
case "flowType": | ||
// TODO: assign flow type to support Pod-to-External flows | ||
if record.Conn.SourcePodName == "" || record.Conn.DestinationPodName == "" { | ||
ie.Value = ipfixregistry.InterNode | ||
} else { | ||
ie.Value = ipfixregistry.IntraNode | ||
} | ||
ie.Value = exp.findFlowType(record) | ||
} | ||
} | ||
|
||
|
@@ -544,3 +547,32 @@ func (exp *flowExporter) sendDataSet() (int, error) { | |
klog.V(4).Infof("Data set sent successfully. Bytes sent: %d", sentBytes) | ||
return sentBytes, nil | ||
} | ||
|
||
func (exp *flowExporter) findFlowType(record flowexporter.FlowRecord) uint8 { | ||
// TODO: support Pod-To-External flows in network policy only mode. | ||
if exp.isNetworkPolicyOnly { | ||
if record.Conn.SourcePodName == "" || record.Conn.DestinationPodName == "" { | ||
return ipfixregistry.InterNode | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you probably should rename these to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As these were used in the context of adding flow types (the function is GetFlowType here), I thought a simple name might be sufficient. If it's confusing, we could change it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, thanks. |
||
} | ||
return ipfixregistry.IntraNode | ||
} | ||
Comment on lines
+551
to
+558
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as discussed with @srikartati offline, I feel like flow type resolution should belong in the Flow Aggregator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @antoninbas. Yes, we have to explore this to support Pod-To-External flows in Nwtqork Policy only mode in the future. |
||
|
||
if exp.nodeRouteController == nil { | ||
klog.Warningf("Can't find flowType without nodeRouteController") | ||
return 0 | ||
} | ||
if exp.nodeRouteController.IPInPodSubnets(record.Conn.TupleOrig.SourceAddress) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will not work for network-policy only mode traffic as the installed node cache indexer is not maintained at all. I think we need to check the network subnet of local There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks Srikar for pointing out it, added a TODO right now and wait for Jianjun's opinion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for adding these lines to address this. My initial assessment on node network based identification is not correct and was mixed up with something else. There is no straightforward way to detect PodIPs at Antrea agent when operating in network policy only mode. |
||
if record.Conn.Mark == openflow.ServiceCTMark || exp.nodeRouteController.IPInPodSubnets(record.Conn.TupleOrig.DestinationAddress) { | ||
if record.Conn.SourcePodName == "" || record.Conn.DestinationPodName == "" { | ||
return ipfixregistry.InterNode | ||
} | ||
return ipfixregistry.IntraNode | ||
} else { | ||
return ipfixregistry.ToExternal | ||
} | ||
} else { | ||
// We do not support External-To-Pod flows for now. | ||
klog.Warningf("Source IP: %s doesn't exist in PodCIDRs", record.Conn.TupleOrig.SourceAddress.String()) | ||
return 0 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ import ( | |
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
ipfixregistry "github.com/vmware/go-ipfix/pkg/registry" | ||
corev1 "k8s.io/api/core/v1" | ||
v1 "k8s.io/api/core/v1" | ||
networkingv1 "k8s.io/api/networking/v1" | ||
|
@@ -40,6 +41,7 @@ DATA SET: | |
DATA RECORD-0: | ||
flowStartSeconds: 1608338066 | ||
flowEndSeconds: 1608338072 | ||
flowEndReason: 2 | ||
sourceTransportPort: 43600 | ||
destinationTransportPort: 5201 | ||
protocolIdentifier: 6 | ||
|
@@ -65,6 +67,7 @@ DATA SET: | |
ingressNetworkPolicyNamespace: antrea-test | ||
egressNetworkPolicyName: test-flow-aggregator-networkpolicy-egress | ||
egressNetworkPolicyNamespace: antrea-test | ||
flowType: 1 | ||
destinationClusterIPv4: 0.0.0.0 | ||
originalExporterIPv4Address: 10.10.0.1 | ||
originalObservationDomainId: 2134708971 | ||
|
@@ -242,8 +245,10 @@ func checkRecordsForFlows(t *testing.T, data *TestData, srcIP string, dstIP stri | |
// Check if record has both Pod name of source and destination pod. | ||
if isIntraNode { | ||
checkPodAndNodeData(t, record, "perftest-a", controlPlaneNodeName(), "perftest-b", controlPlaneNodeName()) | ||
checkFlowType(t, record, ipfixregistry.IntraNode) | ||
} else { | ||
checkPodAndNodeData(t, record, "perftest-a", controlPlaneNodeName(), "perftest-c", workerNodeName(1)) | ||
checkFlowType(t, record, ipfixregistry.InterNode) | ||
} | ||
|
||
if checkService { | ||
|
@@ -336,6 +341,11 @@ func checkBandwidthFromRecord(t *testing.T, record, bandwidth string) { | |
} | ||
} | ||
|
||
// TODO: Add a test that checks the functionality of Pod-To-External flow. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this TODO seems out-of-place on this function, maybe it should have been part of the commit message |
||
func checkFlowType(t *testing.T, record string, flowType uint8) { | ||
assert.Containsf(t, record, fmt.Sprintf("%s: %d", "flowType", flowType), "Record does not have correct flowType") | ||
} | ||
|
||
func getRecordsFromOutput(output string) []string { | ||
re := regexp.MustCompile("(?m)^.*" + "#" + ".*$[\r\n]+") | ||
output = re.ReplaceAllString(output, "") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a simple unit test for this method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, added a unit test for IPInPodSubnets function.
For Pod-To-External flows, I have tested manually by watching the records on the ipfix-collector side.