HDFS-14305. Fix serial number calculation in BlockTokenSecretManager to avoid token key ID overlap between NameNodes. Contributed by He Xiaoqiao.

This commit is contained in:
Erik Krogen 2019-02-28 08:48:10 -08:00 committed by Erik Krogen
parent d045f02a8d
commit af16db86d4
2 changed files with 45 additions and 7 deletions

View File

@ -63,6 +63,17 @@ public class BlockTokenSecretManager extends
public static final Token<BlockTokenIdentifier> DUMMY_TOKEN = new Token<BlockTokenIdentifier>();
/**
* In order to prevent serial No. of different NameNode from overlapping,
* Using 6 bits (identify 64=2^6 namenodes, and presuppose that no scenario
* where deploy more than 64 namenodes (include ANN, SBN, Observers, etc.)
* in one namespace) to identify index of NameNode, and the remainder 26 bits
* auto-incr to change the serial No.
*/
@VisibleForTesting
public static final int NUM_VALID_BITS = 26;
private static final int LOW_MASK = (1 << NUM_VALID_BITS) - 1;
private final boolean isMaster;
/**
@ -79,8 +90,8 @@ public class BlockTokenSecretManager extends
private String blockPoolId;
private final String encryptionAlgorithm;
private final int intRange;
private final int nnRangeStart;
private final int nnIndex;
private final boolean useProto;
private final SecureRandom nonceGenerator = new SecureRandom();
@ -129,8 +140,7 @@ public class BlockTokenSecretManager extends
private BlockTokenSecretManager(boolean isMaster, long keyUpdateInterval,
long tokenLifetime, String blockPoolId, String encryptionAlgorithm,
int nnIndex, int numNNs, boolean useProto) {
this.intRange = Integer.MAX_VALUE / numNNs;
this.nnRangeStart = intRange * nnIndex;
this.nnIndex = nnIndex;
this.isMaster = isMaster;
this.keyUpdateInterval = keyUpdateInterval;
this.tokenLifetime = tokenLifetime;
@ -144,8 +154,7 @@ public class BlockTokenSecretManager extends
@VisibleForTesting
public synchronized void setSerialNo(int serialNo) {
// we mod the serial number by the range and then add that times the index
this.serialNo = (serialNo % intRange) + (nnRangeStart);
this.serialNo = (serialNo & LOW_MASK) | (nnIndex << NUM_VALID_BITS);
}
public void setBlockPoolId(String blockPoolId) {

View File

@ -116,7 +116,36 @@ public class TestFailoverWithBlockTokensEnabled {
}
}
}
@Test
public void testSerialNumberMaskMatchIndex() {
BlockTokenSecretManager btsm1 = cluster.getNamesystem(0).getBlockManager()
.getBlockTokenSecretManager();
BlockTokenSecretManager btsm2 = cluster.getNamesystem(1).getBlockManager()
.getBlockTokenSecretManager();
BlockTokenSecretManager btsm3 = cluster.getNamesystem(2).getBlockManager()
.getBlockTokenSecretManager();
int[] testSet = {0, Integer.MAX_VALUE, Integer.MIN_VALUE,
Integer.MAX_VALUE / 2, Integer.MIN_VALUE / 2,
Integer.MAX_VALUE / 3, Integer.MIN_VALUE / 3};
for (int i = 0; i < testSet.length; i++) {
setAndCheckHighBitsSerialNumber(testSet[i], btsm1, 0);
setAndCheckHighBitsSerialNumber(testSet[i], btsm2, 1);
setAndCheckHighBitsSerialNumber(testSet[i], btsm3, 2);
}
}
/**
* Check mask of serial number if equal to index of NameNode.
*/
private void setAndCheckHighBitsSerialNumber(int serialNumber,
BlockTokenSecretManager btsm, int nnIndex) {
btsm.setSerialNo(serialNumber);
int serialNo = btsm.getSerialNoForTesting();
int index = serialNo >> BlockTokenSecretManager.NUM_VALID_BITS;
assertEquals(index, nnIndex);
}
@Test
public void ensureInvalidBlockTokensAreRejected() throws IOException,
URISyntaxException {