From 91079f0923cc7ad85d98fa3ee09dc0b4e4436e49 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Tue, 24 Sep 2024 14:38:00 +0200 Subject: [PATCH] Implement cluster-wide deterministic MAC generator MACGeneratorClusterDeterministic generates the same MAC address for a given app interface on every node in the cluster. Additionally, the probability of MAC address conflict with other devices outside the cluster is very low (same property that MACGeneratorGloballyScoped provides). Signed-off-by: Milan Lenco --- pkg/pillar/cmd/zedrouter/appnetwork.go | 4 +++- pkg/pillar/cmd/zedrouter/ipam.go | 13 +++++++++++-- pkg/pillar/types/zedroutertypes.go | 6 ++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/pillar/cmd/zedrouter/appnetwork.go b/pkg/pillar/cmd/zedrouter/appnetwork.go index 0420911b9c..1e8dcf7a78 100644 --- a/pkg/pillar/cmd/zedrouter/appnetwork.go +++ b/pkg/pillar/cmd/zedrouter/appnetwork.go @@ -418,7 +418,9 @@ func (z *zedrouter) selectMACGeneratorForApp(status *types.AppNetworkStatus) err macGenerator, _, err := z.appMACGeneratorMap.Get(appKey) if err != nil || macGenerator == types.MACGeneratorUnspecified { // New app or an existing app but without MAC generator ID persisted. - if z.localLegacyMACAddr { + if z.withKubeNetworking { + macGenerator = types.MACGeneratorClusterDeterministic + } else if z.localLegacyMACAddr { // Use older node-scoped MAC address generator. macGenerator = types.MACGeneratorNodeScoped } else { diff --git a/pkg/pillar/cmd/zedrouter/ipam.go b/pkg/pillar/cmd/zedrouter/ipam.go index cbb72952fb..23878bd737 100644 --- a/pkg/pillar/cmd/zedrouter/ipam.go +++ b/pkg/pillar/cmd/zedrouter/ipam.go @@ -49,7 +49,16 @@ func (z *zedrouter) generateAppMac(adapterNum int, appStatus *types.AppNetworkSt h.Write(netInstStatus.UUIDandVersion.UUID[:]) nums := make([]byte, 2) nums[0] = byte(adapterNum) - nums[1] = byte(appStatus.AppNum) + if appStatus.MACGenerator != types.MACGeneratorClusterDeterministic { + // Skipped for MACGeneratorClusterDeterministic. + // Appending AppNum into the hash calculation could result in cluster + // nodes generating different MAC address for the same app interface. + // This is because the order of application config processing can + // differ between nodes. + // This is undesirable. When application is rescheduled to another node, + // the aim is to preserve MAC addresses of its interfaces. + nums[1] = byte(appStatus.AppNum) + } h.Write(nums) hash := h.Sum(nil) switch netInstStatus.Type { @@ -63,7 +72,7 @@ func (z *zedrouter) generateAppMac(adapterNum int, appStatus *types.AppNetworkSt case types.MACGeneratorNodeScoped: return net.HardwareAddr{0x00, 0x16, 0x3e, 0x00, byte(adapterNum), byte(appStatus.AppNum)} - case types.MACGeneratorGloballyScoped: + case types.MACGeneratorGloballyScoped, types.MACGeneratorClusterDeterministic: mac := net.HardwareAddr{hash[0], hash[1], hash[2], hash[3], hash[4], hash[5]} // Mark this MAC address as unicast by setting the I/G bit to zero. mac[0] &= ^byte(1) diff --git a/pkg/pillar/types/zedroutertypes.go b/pkg/pillar/types/zedroutertypes.go index 92dcc9f0e1..7388e1487d 100644 --- a/pkg/pillar/types/zedroutertypes.go +++ b/pkg/pillar/types/zedroutertypes.go @@ -1360,4 +1360,10 @@ const ( // MACGeneratorGloballyScoped generates MAC addresses which are with high probability // unique globally, i.e. across entire fleet of devices. MACGeneratorGloballyScoped = 2 + // MACGeneratorClusterDeterministic generates the same MAC address for a given + // app interface on every node in the cluster. + // Additionally, the probability of MAC address conflict with other devices outside + // the cluster is very low (same property that MACGeneratorGloballyScoped + // provides). + MACGeneratorClusterDeterministic = 3 )