Skip to content

Commit

Permalink
Implement cluster-wide deterministic MAC generator
Browse files Browse the repository at this point in the history
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 <milan@zededa.com>
  • Loading branch information
milan-zededa authored and OhmSpectator committed Oct 17, 2024
1 parent 6900ef1 commit 91079f0
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 3 deletions.
4 changes: 3 additions & 1 deletion pkg/pillar/cmd/zedrouter/appnetwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
13 changes: 11 additions & 2 deletions pkg/pillar/cmd/zedrouter/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions pkg/pillar/types/zedroutertypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

0 comments on commit 91079f0

Please sign in to comment.