ONOS-4505: Bug Fixes
Change-Id: Ia030aa3aff9e2ad34a5e27fbe4ba088dda65bfa7
diff --git a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java
old mode 100755
new mode 100644
index c12c520..f16aeb4
--- a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java
+++ b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/Controller.java
@@ -19,6 +19,7 @@
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.AdaptiveReceiveBufferSizePredictor;
import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
@@ -35,10 +36,14 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import static org.onlab.util.Tools.groupedThreads;
@@ -48,12 +53,17 @@
public class Controller {
protected static final int BUFFER_SIZE = 4 * 1024 * 1024;
private static final Logger log = LoggerFactory.getLogger(Controller.class);
+ private static final int RETRY_INTERVAL = 4;
private final int peerWorkerThreads = 16;
+ byte[] configPacket = null;
private List<IsisProcess> processes = null;
private IsisChannelHandler isisChannelHandler;
private NioClientSocketChannelFactory peerExecFactory;
private ClientBootstrap peerBootstrap = null;
private TpPort isisPort = TpPort.tpPort(IsisConstants.SPORT);
+ private ScheduledExecutorService connectExecutor = null;
+ private int connectRetryCounter = 0;
+ private int connectRetryTime;
/**
* Deactivates ISIS controller.
@@ -70,12 +80,11 @@
*/
public void updateConfig(JsonNode jsonNode) throws Exception {
log.debug("Controller::UpdateConfig called");
- byte[] configPacket = new byte[IsisConstants.CONFIG_LENGTH];
+ configPacket = new byte[IsisConstants.CONFIG_LENGTH];
byte numberOfInterface = 0; // number of interfaces to configure
configPacket[0] = (byte) 0xFF; // its a conf packet - identifier
List<IsisProcess> isisProcesses = getConfig(jsonNode);
-
for (IsisProcess isisProcess : isisProcesses) {
log.debug("IsisProcessDetails : " + isisProcess);
for (IsisInterface isisInterface : isisProcess.isisInterfaceList()) {
@@ -100,16 +109,19 @@
configPacket[1] = numberOfInterface;
//First time configuration
if (processes == null) {
- processes = isisProcesses;
- //Initialize connection by creating a channel handler instance and sent the config packet);
- initConnection();
- //Initializing the interface map in channel handler
- isisChannelHandler.initializeInterfaceMap();
+ if (isisProcesses.size() > 0) {
+ processes = isisProcesses;
+ connectPeer();
+ //Initializing the interface map in channel handler
+ if (isisChannelHandler != null) {
+ isisChannelHandler.initializeInterfaceMap();
+ }
+ }
} else {
isisChannelHandler.updateInterfaceMap(isisProcesses);
+ //Send the config packet
+ isisChannelHandler.sentConfigPacket(configPacket);
}
- //Send the config packet
- isisChannelHandler.sentConfigPacket(configPacket);
}
/**
@@ -182,10 +194,8 @@
* @return list of processes configured
*/
private List<IsisProcess> getConfig(JsonNode json) throws Exception {
-
List<IsisProcess> isisProcessesList = new ArrayList<>();
JsonNode jsonNodes = json;
-
if (jsonNodes == null) {
return isisProcessesList;
}
@@ -193,49 +203,335 @@
List<IsisInterface> interfaceList = new ArrayList<>();
for (JsonNode jsonNode1 : jsonNode.path(IsisConstants.INTERFACE)) {
IsisInterface isisInterface = new DefaultIsisInterface();
- isisInterface.setInterfaceIndex(jsonNode1.path(IsisConstants.INTERFACEINDEX).asInt());
- isisInterface.setInterfaceIpAddress(Ip4Address.valueOf(jsonNode1
- .path(IsisConstants.INTERFACEIP)
- .asText()));
- try {
- isisInterface.setNetworkMask(InetAddress.getByName((jsonNode1
- .path(IsisConstants.NETWORKMASK).asText())).getAddress());
- } catch (UnknownHostException e) {
- log.debug("Error:: Parsing network mask");
+ String index = jsonNode1.path(IsisConstants.INTERFACEINDEX).asText();
+ if (isPrimitive(index)) {
+ int input = Integer.parseInt(index);
+ if (input < 1 || input > 255) {
+ log.debug("Wrong interface index: {}", index);
+ continue;
+ }
+ isisInterface.setInterfaceIndex(Integer.parseInt(index));
+ } else {
+ log.debug("Wrong interface index {}", index);
+ continue;
}
- isisInterface.setInterfaceMacAddress(MacAddress.valueOf(jsonNode1
- .path(IsisConstants.MACADDRESS)
- .asText()));
+ Ip4Address ipAddress = getInterfaceIp(isisInterface.interfaceIndex());
+ if (ipAddress != null && !ipAddress.equals(IsisConstants.DEFAULTIP)) {
+ isisInterface.setInterfaceIpAddress(ipAddress);
+ } else {
+ log.debug("Wrong interface index {}. No matching interface in system.", index);
+ continue;
+ }
+ MacAddress macAddress = getInterfaceMac(isisInterface.interfaceIndex());
+ if (macAddress != null) {
+ isisInterface.setInterfaceMacAddress(macAddress);
+ } else {
+ log.debug("Wrong interface index {}. No matching interface in system.", index);
+ continue;
+ }
+ String mask = getInterfaceMask(isisInterface.interfaceIndex());
+ if (mask != null) {
+ try {
+ isisInterface.setNetworkMask(InetAddress.getByName(mask).getAddress());
+ } catch (UnknownHostException e) {
+ log.debug("Wrong interface index {}. Error while getting network mask.", index);
+ }
+ } else {
+ log.debug("Wrong interface index {}. Error while getting network mask.", index);
+ continue;
+ }
isisInterface.setIntermediateSystemName(jsonNode1
.path(IsisConstants.INTERMEDIATESYSTEMNAME)
.asText());
- isisInterface.setSystemId(jsonNode1.path(IsisConstants.SYSTEMID).asText());
- isisInterface.setReservedPacketCircuitType(jsonNode1
- .path(IsisConstants.RESERVEDPACKETCIRCUITTYPE)
- .asInt());
- if (isisInterface.reservedPacketCircuitType() == IsisRouterType.L1.value()) {
- isisInterface.setL1LanId(jsonNode1.path(IsisConstants.LANID).asText());
+ String systemId = jsonNode1.path(IsisConstants.SYSTEMID).asText();
+ if (isValidSystemId(systemId)) {
+ isisInterface.setSystemId(systemId);
+ } else {
+ log.debug("Wrong systemId: {} for interface index {}.", systemId, index);
+ continue;
}
- isisInterface.setIdLength(jsonNode1.path(IsisConstants.IDLENGTH).asInt());
- isisInterface.setMaxAreaAddresses(jsonNode1.path(IsisConstants.MAXAREAADDRESSES).asInt());
- isisInterface.setNetworkType(IsisNetworkType.get(jsonNode1
- .path(IsisConstants.NETWORKTYPE)
- .asInt()));
- isisInterface.setAreaAddress(jsonNode1.path(IsisConstants.AREAADDRESS).asText());
- isisInterface.setAreaLength(jsonNode1.path(IsisConstants.AREALENGTH).asInt());
- isisInterface.setLspId(jsonNode1.path(IsisConstants.LSPID).asText());
- isisInterface.setCircuitId(jsonNode1.path(IsisConstants.CIRCUITID).asText());
- isisInterface.setHoldingTime(jsonNode1.path(IsisConstants.HOLDINGTIME).asInt());
- isisInterface.setPriority(jsonNode1.path(IsisConstants.PRIORITY).asInt());
- isisInterface.setHelloInterval(jsonNode1.path(IsisConstants.HELLOINTERVAL).asInt());
+ String circuitType = jsonNode1.path(IsisConstants.RESERVEDPACKETCIRCUITTYPE).asText();
+ if (isPrimitive(circuitType)) {
+ int input = Integer.parseInt(circuitType);
+ if (input < 1 || input > 3) {
+ log.debug("Wrong ReservedPacketCircuitType: {} for interface index {}.", circuitType, index);
+ continue;
+ }
+ isisInterface.setReservedPacketCircuitType(input);
+ } else {
+ log.debug("Wrong ReservedPacketCircuitType: {} for interface index {}.", circuitType, index);
+ continue;
+ }
+ String networkType = jsonNode1.path(IsisConstants.NETWORKTYPE).asText();
+ if (isPrimitive(networkType)) {
+ int input = Integer.parseInt(networkType);
+ if (input < 1 || input > 2) {
+ log.debug("Wrong networkType: {} for interface index {}.", networkType, index);
+ continue;
+ }
+ isisInterface.setNetworkType(IsisNetworkType.get(input));
+ } else {
+ log.debug("Wrong networkType: {} for interface index {}.", networkType, index);
+ continue;
+ }
+ String areaAddress = jsonNode1.path(IsisConstants.AREAADDRESS).asText();
+ if (isPrimitive(areaAddress)) {
+ if (areaAddress.length() > 7) {
+ log.debug("Wrong areaAddress: {} for interface index {}.", areaAddress, index);
+ continue;
+ }
+ isisInterface.setAreaAddress(areaAddress);
+ } else {
+ log.debug("Wrong areaAddress: {} for interface index {}.", areaAddress, index);
+ continue;
+ }
+ String circuitId = jsonNode1.path(IsisConstants.CIRCUITID).asText();
+ if (isPrimitive(circuitId)) {
+ int input = Integer.parseInt(circuitId);
+ if (input < 1) {
+ log.debug("Wrong circuitId: {} for interface index {}.", circuitId, index);
+ continue;
+ }
+ isisInterface.setCircuitId(circuitId);
+ } else {
+ log.debug("Wrong circuitId: {} for interface index {}.", circuitId, index);
+ continue;
+ }
+ String holdingTime = jsonNode1.path(IsisConstants.HOLDINGTIME).asText();
+ if (isPrimitive(holdingTime)) {
+ int input = Integer.parseInt(holdingTime);
+ if (input < 1 || input > 255) {
+ log.debug("Wrong holdingTime: {} for interface index {}.", holdingTime, index);
+ continue;
+ }
+ isisInterface.setHoldingTime(input);
+ } else {
+ log.debug("Wrong holdingTime: {} for interface index {}.", holdingTime, index);
+ continue;
+ }
+ String helloInterval = jsonNode1.path(IsisConstants.HELLOINTERVAL).asText();
+ if (isPrimitive(helloInterval)) {
+ int interval = Integer.parseInt(helloInterval);
+ if (interval > 0 && interval <= 255) {
+ isisInterface.setHelloInterval(interval);
+ } else {
+ log.debug("Wrong hello interval: {} for interface index {}.", helloInterval, index);
+ continue;
+ }
+ } else {
+ log.debug("Wrong hello interval: {} for interface index {}.", helloInterval, index);
+ continue;
+ }
interfaceList.add(isisInterface);
}
- IsisProcess process = new DefaultIsisProcess();
- process.setProcessId(jsonNode.path(IsisConstants.PROCESSESID).asText());
- process.setIsisInterfaceList(interfaceList);
- isisProcessesList.add(process);
+ if (interfaceList.size() > 0) {
+ IsisProcess process = new DefaultIsisProcess();
+ process.setProcessId(jsonNode.path(IsisConstants.PROCESSESID).asText());
+ process.setIsisInterfaceList(interfaceList);
+ isisProcessesList.add(process);
+ }
});
return isisProcessesList;
}
+
+ /**
+ * Returns interface MAC by index.
+ *
+ * @param interfaceIndex interface index
+ * @return interface IP by index
+ */
+ private MacAddress getInterfaceMac(int interfaceIndex) {
+ MacAddress macAddress = null;
+ try {
+ NetworkInterface networkInterface = NetworkInterface.getByIndex(interfaceIndex);
+ macAddress = MacAddress.valueOf(networkInterface.getHardwareAddress());
+ } catch (Exception e) {
+ log.debug("Error while getting Interface IP by index");
+ return macAddress;
+ }
+
+ return macAddress;
+ }
+
+ /**
+ * Returns interface IP by index.
+ *
+ * @param interfaceIndex interface index
+ * @return interface IP by index
+ */
+ private Ip4Address getInterfaceIp(int interfaceIndex) {
+ Ip4Address ipAddress = null;
+ try {
+ NetworkInterface networkInterface = NetworkInterface.getByIndex(interfaceIndex);
+ Enumeration ipAddresses = networkInterface.getInetAddresses();
+ while (ipAddresses.hasMoreElements()) {
+ InetAddress address = (InetAddress) ipAddresses.nextElement();
+ if (!address.isLinkLocalAddress()) {
+ ipAddress = Ip4Address.valueOf(address.getAddress());
+ break;
+ }
+ }
+ } catch (Exception e) {
+ log.debug("Error while getting Interface IP by index");
+ return IsisConstants.DEFAULTIP;
+ }
+ return ipAddress;
+ }
+
+ /**
+ * Returns interface MAC by index.
+ *
+ * @param interfaceIndex interface index
+ * @return interface IP by index
+ */
+ private String getInterfaceMask(int interfaceIndex) {
+ String subnetMask = null;
+ try {
+ Ip4Address ipAddress = getInterfaceIp(interfaceIndex);
+ NetworkInterface networkInterface = NetworkInterface.getByInetAddress(
+ InetAddress.getByName(ipAddress.toString()));
+ Enumeration ipAddresses = networkInterface.getInetAddresses();
+ int index = 0;
+ while (ipAddresses.hasMoreElements()) {
+ InetAddress address = (InetAddress) ipAddresses.nextElement();
+ if (!address.isLinkLocalAddress()) {
+ break;
+ }
+ index++;
+ }
+ int prfLen = networkInterface.getInterfaceAddresses().get(index).getNetworkPrefixLength();
+ int shft = 0xffffffff << (32 - prfLen);
+ int oct1 = ((byte) ((shft & 0xff000000) >> 24)) & 0xff;
+ int oct2 = ((byte) ((shft & 0x00ff0000) >> 16)) & 0xff;
+ int oct3 = ((byte) ((shft & 0x0000ff00) >> 8)) & 0xff;
+ int oct4 = ((byte) (shft & 0x000000ff)) & 0xff;
+ subnetMask = oct1 + "." + oct2 + "." + oct3 + "." + oct4;
+ } catch (Exception e) {
+ log.debug("Error while getting Interface network mask by index");
+ return subnetMask;
+ }
+ return subnetMask;
+ }
+
+ /**
+ * Checks if primitive or not.
+ *
+ * @param value input value
+ * @return true if number else false
+ */
+ private boolean isPrimitive(String value) {
+ boolean status = true;
+ value = value.trim();
+ if (value.length() < 1) {
+ return false;
+ }
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ if (!Character.isDigit(c)) {
+ status = false;
+ break;
+ }
+ }
+
+ return status;
+ }
+
+ /**
+ * Checks if system id is valid or not.
+ *
+ * @param value input value
+ * @return true if valid else false
+ */
+ private boolean isValidSystemId(String value) {
+ value = value.trim();
+ boolean status = true;
+ if (value.length() != 14) {
+ return false;
+ }
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ if (!Character.isDigit(c)) {
+ if (!((i == 4 || i == 9) && c == '.')) {
+ status = false;
+ break;
+ }
+ }
+ }
+
+ return status;
+ }
+
+ /**
+ * Disconnects the executor.
+ */
+ public void disconnectExecutor() {
+ if (connectExecutor != null) {
+ connectExecutor.shutdown();
+ connectExecutor = null;
+ }
+ }
+
+ /**
+ * Connects to peer.
+ */
+ public void connectPeer() {
+ scheduleConnectionRetry(this.connectRetryTime);
+ }
+
+ /**
+ * Retry connection with exponential back-off mechanism.
+ *
+ * @param retryDelay retry delay
+ */
+ private void scheduleConnectionRetry(long retryDelay) {
+ if (this.connectExecutor == null) {
+ this.connectExecutor = Executors.newSingleThreadScheduledExecutor();
+ }
+ this.connectExecutor.schedule(new ConnectionRetry(), retryDelay, TimeUnit.MINUTES);
+ }
+
+ /**
+ * Implements ISIS connection and manages connection to peer with back-off mechanism in case of failure.
+ */
+ class ConnectionRetry implements Runnable {
+ @Override
+ public void run() {
+ log.debug("Connect to peer {}", IsisConstants.SHOST);
+ initConnection();
+ InetSocketAddress connectToSocket = new InetSocketAddress(IsisConstants.SHOST, isisPort.toInt());
+ try {
+ peerBootstrap.connect(connectToSocket).addListener(new ChannelFutureListener() {
+ @Override
+ public void operationComplete(ChannelFuture future) throws Exception {
+ if (!future.isSuccess()) {
+ connectRetryCounter++;
+ log.error("Connection failed, ConnectRetryCounter {} remote host {}", connectRetryCounter,
+ IsisConstants.SHOST);
+ /*
+ * Reconnect to peer on failure is exponential till 4 mins, later on retry after every 4
+ * mins.
+ */
+ if (connectRetryTime < RETRY_INTERVAL) {
+ connectRetryTime = (connectRetryTime != 0) ? connectRetryTime * 2 : 1;
+ }
+ scheduleConnectionRetry(connectRetryTime);
+ } else {
+ connectRetryCounter++;
+ log.info("Connected to remote host {}, Connect Counter {}", IsisConstants.SHOST,
+ connectRetryCounter);
+ disconnectExecutor();
+ isisChannelHandler.initializeInterfaceMap();
+ //Send the config packet
+ isisChannelHandler.sentConfigPacket(configPacket);
+ return;
+ }
+ }
+ });
+ } catch (Exception e) {
+ log.info("Connect peer exception : " + e.toString());
+ disconnectExecutor();
+ }
+ }
+ }
}
\ No newline at end of file