[SEBA-624] Implementation of radius server operational status
Cherry-picked from aaa-1.10
Change-Id: I3b70ddfc45c4b9e57c587df671088580c7426a89
diff --git a/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEvent.java b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEvent.java
new file mode 100644
index 0000000..7ba9534
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEvent.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.aaa;
+
+import org.onosproject.event.AbstractEvent;
+
+public class RadiusOperationalStatusEvent extends
+ AbstractEvent<RadiusOperationalStatusEvent.Type, String> {
+
+ public RadiusOperationalStatusEvent(Type type, String subject) {
+ super(type, subject);
+ }
+
+ public enum Type {
+ RADIUS_OPERATIONAL_STATUS
+ }
+
+}
diff --git a/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEventDelegate.java b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEventDelegate.java
new file mode 100644
index 0000000..f4d5d5d
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEventDelegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.aaa;
+
+import org.onosproject.store.StoreDelegate;
+
+public interface RadiusOperationalStatusEventDelegate
+ extends StoreDelegate<RadiusOperationalStatusEvent> {
+
+}
diff --git a/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEventListener.java b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEventListener.java
new file mode 100644
index 0000000..defffcc
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusEventListener.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.aaa;
+
+import org.onosproject.event.EventListener;
+
+public interface RadiusOperationalStatusEventListener extends
+ EventListener<RadiusOperationalStatusEvent> {
+
+}
diff --git a/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusService.java b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusService.java
new file mode 100644
index 0000000..10c5d8b
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/RadiusOperationalStatusService.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.aaa;
+
+import org.onlab.packet.RADIUS;
+import org.onosproject.event.ListenerService;
+
+/**
+ * Service for interacting with operational status module.
+ */
+
+public interface RadiusOperationalStatusService extends
+ ListenerService<RadiusOperationalStatusEvent, RadiusOperationalStatusEventListener> {
+ /**
+ * Return RadiusOperationalStatusEventDelegate object.
+ *
+ * @return RadiusOperationalStatusEventDelegate
+ */
+ RadiusOperationalStatusEventDelegate getRadiusOprStDelegate();
+
+ /**
+ * Return String object.
+ *
+ * @return String
+ */
+ String getRadiusServerOperationalStatus();
+
+ /**
+ * Set the value of statusServerReqSent flag.
+ *
+ * @param statusServerReqSent statusServerReqSent flag
+ */
+ void setStatusServerReqSent(boolean statusServerReqSent);
+
+ /**
+ * Set the value of radiusOperationalStatus Evaluation Mode.
+ *
+ * @param radiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode value
+ */
+ void setRadiusOperationalStatusEvaluationMode(
+ RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode);
+
+ /**
+ * Set the value of Operational Status Server Timeout In Milliseconds.
+ *
+ * @param operationalStatusServerTimeoutInMillis operationalStatusServerTimeoutInMillis
+ */
+ void setOperationalStatusServerTimeoutInMillis(long operationalStatusServerTimeoutInMillis);
+
+ /**
+ * Determine the operational status of server.
+ */
+ void checkServerOperationalStatus();
+
+ /**
+ * Check if radius response is for operational status.
+ *
+ * @param identifier identifier value of radius packet
+ * @return boolean
+ */
+ boolean isRadiusResponseForOperationalStatus(byte identifier);
+
+ /**
+ * handle incoming radius packet for operational status.
+ *
+ * @param radiusPacket radiusPacket of incoming operational status
+ */
+ void handleRadiusPacketForOperationalStatus(RADIUS radiusPacket);
+
+ /**
+ * initialize radiusOperationalStatusService.
+ *
+ * @param address address of radius server
+ * @param secret secret key for radius server
+ * @param impl impl of RadiusCommunicator
+ */
+ void initialize(byte[] address, String secret, RadiusCommunicator impl);
+
+ /**
+ * set packet outgoing time in milliseconds.
+ *
+ * @param identifier identifier of outgoing packet
+ */
+ void setOutTimeInMillis(byte identifier);
+
+ enum OperationalStatus {
+ UNAVAILABLE,
+ UNKNOWN,
+ IN_USE,
+ }
+
+ enum RadiusOperationalStatusEvaluationMode {
+
+ STATUS_REQUEST, ACCESS_REQUEST, AUTO;
+
+ public static RadiusOperationalStatusEvaluationMode getValue(String value) {
+
+ for (RadiusOperationalStatusEvaluationMode mode: RadiusOperationalStatusEvaluationMode.values()) {
+ if (mode.toString().equalsIgnoreCase(value)) {
+ return mode;
+ }
+ }
+ return null;
+ }
+ }
+
+}
diff --git a/app/src/main/java/org/opencord/aaa/impl/AaaManager.java b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
old mode 100755
new mode 100644
index 55b6726..0e819d9
--- a/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
+++ b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
@@ -15,23 +15,8 @@
*/
package org.opencord.aaa.impl;
-import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.Arrays;
-import java.util.List;
-
+import com.google.common.base.Strings;
import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Reference;
-import org.osgi.service.component.annotations.ReferenceCardinality;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.EAP;
import org.onlab.packet.EAPOL;
@@ -71,31 +56,56 @@
import org.opencord.aaa.AuthenticationStatisticsEvent;
import org.opencord.aaa.AuthenticationStatisticsService;
import org.opencord.aaa.RadiusCommunicator;
+import org.opencord.aaa.RadiusOperationalStatusEvent;
+import org.opencord.aaa.RadiusOperationalStatusService;
+import org.opencord.aaa.RadiusOperationalStatusService.RadiusOperationalStatusEvaluationMode;
import org.opencord.aaa.StateMachineDelegate;
import org.opencord.sadis.BaseInformationService;
import org.opencord.sadis.SadisService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
import org.osgi.service.component.ComponentContext;
-import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
-import com.google.common.base.Strings;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_EVENT;
-import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_EVENT_DEFAULT;
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_EVENT_GENERATION;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_TIMEOUT;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_PERIOD;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_GENERATION_PERIOD_DEFAULT;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.STATUS_SERVER_MODE;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.STATUS_SERVER_MODE_DEFAULT;
+import static org.slf4j.LoggerFactory.getLogger;
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
/**
* AAA application for ONOS.
*/
@Component(immediate = true, property = {
- STATISTICS_GENERATION_EVENT + ":Integer=" + STATISTICS_GENERATION_EVENT_DEFAULT,
+ STATISTICS_GENERATION_PERIOD + ":Integer=" + STATISTICS_GENERATION_PERIOD_DEFAULT,
+ OPERATIONAL_STATUS_SERVER_EVENT_GENERATION + ":Integer=" + OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT,
+ OPERATIONAL_STATUS_SERVER_TIMEOUT + ":Integer=" + OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT,
+ STATUS_SERVER_MODE + ":String=" + STATUS_SERVER_MODE_DEFAULT,
})
public class AaaManager
extends AbstractListenerManager<AuthenticationEvent, AuthenticationEventListener>
@@ -129,12 +139,18 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected ComponentConfigService cfgService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected RadiusOperationalStatusService radiusOperationalStatusService;
+
protected AuthenticationStatisticsEventPublisher authenticationStatisticsPublisher;
protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
private final DeviceListener deviceListener = new InternalDeviceListener();
- /** Statistics generation interval. */
- private int statisticsGenerationEvent = STATISTICS_GENERATION_EVENT_DEFAULT;
+ // Properties
+ private int statisticsGenerationPeriodInSeconds = STATISTICS_GENERATION_PERIOD_DEFAULT;
+ private int operationalStatusEventGenerationPeriodInSeconds = OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT;
+ private int operationalStatusServerTimeoutInSeconds = OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT;
+ protected String operationalStatusEvaluationMode = STATUS_SERVER_MODE_DEFAULT;
// NAS IP address
protected InetAddress nasIpAddress;
@@ -181,7 +197,7 @@
AaaConfig newCfg;
ScheduledFuture<?> scheduledFuture;
-
+ ScheduledFuture<?> scheduledStatusServerChecker;
ScheduledExecutorService executor;
String configuredAaaServerAddress;
HashSet<Byte> outPacketSet = new HashSet<Byte>();
@@ -261,11 +277,15 @@
impl.requestIntercepts();
deviceService.addListener(deviceListener);
getConfiguredAaaServerAddress();
+ radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
authenticationStatisticsPublisher =
new AuthenticationStatisticsEventPublisher();
- executor = Executors.newScheduledThreadPool(1);
+ executor = Executors.newScheduledThreadPool(3);
+
scheduledFuture = executor.scheduleAtFixedRate(authenticationStatisticsPublisher,
- 0, statisticsGenerationEvent, TimeUnit.SECONDS);
+ 0, statisticsGenerationPeriodInSeconds, TimeUnit.SECONDS);
+ scheduledStatusServerChecker = executor.scheduleAtFixedRate(new ServerStatusChecker(), 0,
+ operationalStatusEventGenerationPeriodInSeconds, TimeUnit.SECONDS);
log.info("Started");
}
@@ -282,16 +302,40 @@
deviceService.removeListener(deviceListener);
eventDispatcher.removeSink(AuthenticationEvent.class);
scheduledFuture.cancel(true);
+ scheduledStatusServerChecker.cancel(true);
executor.shutdown();
log.info("Stopped");
}
-
@Modified
public void modified(ComponentContext context) {
- Dictionary<?, ?> properties = context.getProperties();
- String s = Tools.get(properties, STATISTICS_GENERATION_EVENT);
- statisticsGenerationEvent = Strings.isNullOrEmpty(s)
- ? STATISTICS_GENERATION_EVENT_DEFAULT : Integer.parseInt(s.trim());
+ Dictionary<String, Object> properties = context.getProperties();
+
+ String s = Tools.get(properties, "statisticsGenerationPeriodInSeconds");
+ statisticsGenerationPeriodInSeconds = Strings.isNullOrEmpty(s) ? STATISTICS_GENERATION_PERIOD_DEFAULT
+ : Integer.parseInt(s.trim());
+
+ s = Tools.get(properties, "operationalStatusEventGenerationPeriodInSeconds");
+ operationalStatusEventGenerationPeriodInSeconds = Strings.isNullOrEmpty(s)
+ ? OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT
+ : Integer.parseInt(s.trim());
+
+ s = Tools.get(properties, "operationalStatusServerTimeoutInSeconds");
+ operationalStatusServerTimeoutInSeconds = Strings.isNullOrEmpty(s) ? OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT
+ : Integer.parseInt(s.trim());
+
+ s = Tools.get(properties, "operationalStatusEvaluationMode");
+ String newEvaluationModeString = Strings.isNullOrEmpty(s) ? STATUS_SERVER_MODE_DEFAULT : s.trim();
+
+ radiusOperationalStatusService
+ .setOperationalStatusServerTimeoutInMillis(operationalStatusServerTimeoutInSeconds * 1000);
+ RadiusOperationalStatusEvaluationMode newEvaluationMode =
+ RadiusOperationalStatusEvaluationMode.getValue(newEvaluationModeString);
+ if (newEvaluationMode != null) {
+ radiusOperationalStatusService.setRadiusOperationalStatusEvaluationMode(newEvaluationMode);
+ operationalStatusEvaluationMode = newEvaluationModeString;
+ } else {
+ properties.put("operationalStatusEvaluationMode", operationalStatusEvaluationMode);
+ }
}
protected void configureRadiusCommunication() {
@@ -381,6 +425,7 @@
outPacketSet.add(radiusPacket.getIdentifier());
aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
+ aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
impl.sendRadiusPacket(radiusPacket, inPkt);
}
@@ -411,6 +456,10 @@
if (log.isTraceEnabled()) {
log.trace("Received RADIUS packet {}", radiusPacket);
}
+ if (radiusOperationalStatusService.isRadiusResponseForOperationalStatus(radiusPacket.getIdentifier())) {
+ radiusOperationalStatusService.handleRadiusPacketForOperationalStatus(radiusPacket);
+ return;
+ }
StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
if (stateMachine == null) {
log.error("Invalid packet identifier {}, could not find corresponding "
@@ -916,5 +965,20 @@
notify(new AuthenticationStatisticsEvent(AuthenticationStatisticsEvent.Type.STATS_UPDATE,
aaaStatisticsManager.getAaaStats()));
}
+ }
+
+ private class ServerStatusChecker implements Runnable {
+ @Override
+ public void run() {
+ log.info("Notifying RadiusOperationalStatusEvent");
+ radiusOperationalStatusService.checkServerOperationalStatus();
+ log.info("--POSTING--" + radiusOperationalStatusService.getRadiusServerOperationalStatus());
+ radiusOperationalStatusService.getRadiusOprStDelegate()
+ .notify(new RadiusOperationalStatusEvent(
+ RadiusOperationalStatusEvent.Type.RADIUS_OPERATIONAL_STATUS,
+ radiusOperationalStatusService.
+ getRadiusServerOperationalStatus()));
}
-}
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/opencord/aaa/impl/OsgiPropertyConstants.java b/app/src/main/java/org/opencord/aaa/impl/OsgiPropertyConstants.java
index 38f1a32..1c59799 100644
--- a/app/src/main/java/org/opencord/aaa/impl/OsgiPropertyConstants.java
+++ b/app/src/main/java/org/opencord/aaa/impl/OsgiPropertyConstants.java
@@ -24,6 +24,16 @@
private OsgiPropertyConstants() {
}
- public static final String STATISTICS_GENERATION_EVENT = "statisticsGenerationEvent";
- public static final int STATISTICS_GENERATION_EVENT_DEFAULT = 20;
+ public static final String STATISTICS_GENERATION_PERIOD = "statisticsGenerationPeriodInSeconds";
+ public static final int STATISTICS_GENERATION_PERIOD_DEFAULT = 20;
+
+ public static final String OPERATIONAL_STATUS_SERVER_EVENT_GENERATION =
+ "operationalStatusEventGenerationPeriodInSeconds";
+ public static final int OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT = 30;
+
+ public static final String OPERATIONAL_STATUS_SERVER_TIMEOUT = "operationalStatusServerTimeoutInSeconds";
+ public static final int OPERATIONAL_STATUS_SERVER_TIMEOUT_DEFAULT = 10;
+
+ public static final String STATUS_SERVER_MODE = "operationalStatusEvaluationMode";
+ public static final String STATUS_SERVER_MODE_DEFAULT = "AUTO";
}
diff --git a/app/src/main/java/org/opencord/aaa/impl/PortBasedRadiusCommunicator.java b/app/src/main/java/org/opencord/aaa/impl/PortBasedRadiusCommunicator.java
index 2967a14..ad00b5f 100755
--- a/app/src/main/java/org/opencord/aaa/impl/PortBasedRadiusCommunicator.java
+++ b/app/src/main/java/org/opencord/aaa/impl/PortBasedRadiusCommunicator.java
@@ -15,17 +15,17 @@
*/
package org.opencord.aaa.impl;
+import com.google.common.collect.Maps;
import org.onlab.packet.ARP;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
-import org.onlab.packet.Ip4Address;
import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
-
import org.onosproject.core.ApplicationId;
import org.onosproject.mastership.MastershipEvent;
import org.onosproject.mastership.MastershipListener;
@@ -43,24 +43,20 @@
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketService;
-
import org.opencord.aaa.AaaConfig;
import org.opencord.aaa.RadiusCommunicator;
import org.opencord.sadis.BaseInformationService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
-
import org.slf4j.Logger;
-import com.google.common.collect.Maps;
-
-import static org.onosproject.net.packet.PacketPriority.CONTROL;
-import static org.slf4j.LoggerFactory.getLogger;
-
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Set;
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.slf4j.LoggerFactory.getLogger;
+
/**
* Handles communication with the RADIUS server through ports
* of the SDN switches.
@@ -260,13 +256,20 @@
if (deviceInfo == null) {
log.warn("No Device found with SN {}", serialNo);
+ aaaManager.radiusOperationalStatusService.setStatusServerReqSent(false);
return;
}
ipToSnMap.put(deviceInfo.ipAddress(), serialNo);
- aaaManager.aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
+ if (radiusPacket.getIdentifier() == RadiusOperationalStatusManager.AAA_REQUEST_ID_STATUS_REQUEST ||
+ radiusPacket.getIdentifier() == RadiusOperationalStatusManager.AAA_REQUEST_ID_FAKE_ACCESS_REQUEST) {
+ aaaManager.radiusOperationalStatusService.setOutTimeInMillis(radiusPacket.getIdentifier());
+ } else {
+ aaaManager.aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
+ }
// send the message out
sendFromRadiusServerPort(pktCustomizer.
customizeEthernetIPHeaders(ethReply, inPkt));
+ aaaManager.radiusOperationalStatusService.setStatusServerReqSent(true);
}
/**
diff --git a/app/src/main/java/org/opencord/aaa/impl/RadiusOperationalStatusManager.java b/app/src/main/java/org/opencord/aaa/impl/RadiusOperationalStatusManager.java
new file mode 100644
index 0000000..2fe5755
--- /dev/null
+++ b/app/src/main/java/org/opencord/aaa/impl/RadiusOperationalStatusManager.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.aaa.impl;
+
+import org.onlab.packet.RADIUS;
+import org.onlab.packet.RADIUSAttribute;
+import org.onosproject.event.AbstractListenerManager;
+import org.opencord.aaa.RadiusCommunicator;
+import org.opencord.aaa.RadiusOperationalStatusEvent;
+import org.opencord.aaa.RadiusOperationalStatusEventDelegate;
+import org.opencord.aaa.RadiusOperationalStatusEventListener;
+import org.opencord.aaa.RadiusOperationalStatusService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+@Component(immediate = true)
+public class RadiusOperationalStatusManager
+ extends AbstractListenerManager<RadiusOperationalStatusEvent, RadiusOperationalStatusEventListener>
+ implements RadiusOperationalStatusService {
+
+ private byte[] address;
+ private String secret;
+ private RadiusCommunicator impl;
+ private RadiusOperationalStatusEventDelegate radiusOprStDelegate;
+
+ private long operationalStatusServerTimeoutInMillis;
+ private boolean statusServerReqSent;
+ private final Logger log = getLogger(getClass());
+
+ private Boolean fakeAccessRequestPacketRecieved = false;
+ private long fakeAccessRequestOutTimeInMillis;
+
+ private Boolean serverStatusPacketRecieved = false;
+ private long serverStatusOutTimeInMillis;
+
+ private OperationalStatus radiusServerOperationalStatus;
+ public static final byte AAA_REQUEST_ID_STATUS_REQUEST = 0;
+ public static final byte AAA_REQUEST_ID_FAKE_ACCESS_REQUEST = 1;
+
+ private RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode;
+
+ private static final String DUMMY_USER = new String("dummy-user");
+ private static final byte RADIUS_CODE_STATUS_REQUEST = (byte) 12;
+ private long lastRadiusPacketInTimeInMillis;
+
+ public void setOperationalStatusServerTimeoutInMillis(long operationalStatusServerTimeoutInMillis) {
+ this.operationalStatusServerTimeoutInMillis = operationalStatusServerTimeoutInMillis;
+ }
+
+ public void setRadiusOperationalStatusEvaluationMode(
+ RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode) {
+ this.radiusOperationalStatusEvaluationMode = radiusOperationalStatusEvaluationMode;
+ }
+
+ public RadiusOperationalStatusEventDelegate getRadiusOprStDelegate() {
+ return radiusOprStDelegate;
+ }
+
+ @Override
+ public void setOutTimeInMillis(byte identifier) {
+ if (identifier == AAA_REQUEST_ID_STATUS_REQUEST) {
+ serverStatusOutTimeInMillis = System.currentTimeMillis();
+ } else {
+ fakeAccessRequestOutTimeInMillis = System.currentTimeMillis();
+ }
+ }
+
+ @Override
+ public String getRadiusServerOperationalStatus() {
+ return radiusServerOperationalStatus.toString();
+ }
+
+ @Activate
+ public void activate() {
+ radiusOprStDelegate = new InternalRadiusOperationalStatusDelegate();
+ eventDispatcher.addSink(RadiusOperationalStatusEvent.class, listenerRegistry);
+ radiusServerOperationalStatus = OperationalStatus.UNKNOWN;
+ }
+
+ public void setStatusServerReqSent(boolean statusServerReqSent) {
+ this.statusServerReqSent = statusServerReqSent;
+ }
+
+ @Deactivate
+ public void deactivate() {
+ eventDispatcher.removeSink(RadiusOperationalStatusEvent.class);
+ }
+
+ public void initialize(byte[] address, String secret, RadiusCommunicator impl) {
+ this.address = address;
+ this.secret = secret;
+ this.impl = impl;
+ }
+
+ public boolean isRadiusResponseForOperationalStatus(byte identifier) {
+ if (identifier == AAA_REQUEST_ID_STATUS_REQUEST || identifier == AAA_REQUEST_ID_FAKE_ACCESS_REQUEST) {
+ return true;
+ } else {
+ lastRadiusPacketInTimeInMillis = System.currentTimeMillis();
+ return false;
+ }
+ }
+
+ public void handleRadiusPacketForOperationalStatus(RADIUS radiusPacket) {
+ byte radiusPktIdentifier = radiusPacket.getIdentifier();
+
+ if (radiusPktIdentifier == AAA_REQUEST_ID_STATUS_REQUEST) {
+ long serverStatusRttInMillis = System.currentTimeMillis() - serverStatusOutTimeInMillis;
+ if (serverStatusRttInMillis < operationalStatusServerTimeoutInMillis) {
+ serverStatusPacketRecieved = true;
+ }
+ } else {
+ long fakeAccessRttInMillis = System.currentTimeMillis() - fakeAccessRequestOutTimeInMillis;
+ if (fakeAccessRttInMillis < operationalStatusServerTimeoutInMillis) {
+ fakeAccessRequestPacketRecieved = true;
+ }
+ }
+
+ switch (radiusPacket.getCode()) {
+ case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
+ synchronized (serverStatusPacketRecieved) {
+ serverStatusPacketRecieved.notify();
+ }
+ break;
+ case RADIUS.RADIUS_CODE_ACCESS_REJECT:
+ synchronized (fakeAccessRequestPacketRecieved) {
+ fakeAccessRequestPacketRecieved.notify();
+ }
+ break;
+ default:
+ log.warn("Unexpected Radius message for operational status recieved "
+ + "with code: {}", radiusPacket.getCode());
+ }
+ }
+
+ public void checkServerStatusUsingStatusServerRequest() throws InterruptedException {
+ RADIUS radiusStatusServerRequest;
+ // identifier = 0 for status server
+ radiusStatusServerRequest = new RADIUS(RADIUS_CODE_STATUS_REQUEST, AAA_REQUEST_ID_STATUS_REQUEST);
+
+ radiusStatusServerRequest.setIdentifier(AAA_REQUEST_ID_STATUS_REQUEST);
+ radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes());
+
+ radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address);
+ radiusStatusServerRequest.addMessageAuthenticator(secret);
+ setOutTimeInMillis(radiusStatusServerRequest.getIdentifier());
+ impl.sendRadiusPacket(radiusStatusServerRequest, null);
+ synchronized (serverStatusPacketRecieved) {
+ serverStatusPacketRecieved.wait(operationalStatusServerTimeoutInMillis);
+ }
+ }
+
+ public void checkServerStatusUsingFakeAccessRequest() throws InterruptedException {
+ RADIUS radiusDummyAccessRequest;
+ // identifier = 1 for fake accessRequest
+ radiusDummyAccessRequest = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, AAA_REQUEST_ID_FAKE_ACCESS_REQUEST);
+
+ radiusDummyAccessRequest.setIdentifier(AAA_REQUEST_ID_FAKE_ACCESS_REQUEST);
+ radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes());
+
+ radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address);
+ radiusDummyAccessRequest.addMessageAuthenticator(secret);
+ setOutTimeInMillis(radiusDummyAccessRequest.getIdentifier());
+ impl.sendRadiusPacket(radiusDummyAccessRequest, null);
+ synchronized (fakeAccessRequestPacketRecieved) {
+ fakeAccessRequestPacketRecieved.wait(operationalStatusServerTimeoutInMillis);
+ }
+ }
+
+ public void checkStatusServerForAccessRequestMode() throws InterruptedException {
+ long radiusResponseRecievedTimeDifference = System.currentTimeMillis() - lastRadiusPacketInTimeInMillis;
+ if (radiusResponseRecievedTimeDifference > operationalStatusServerTimeoutInMillis) {
+ checkServerStatusUsingFakeAccessRequest();
+ if (statusServerReqSent && fakeAccessRequestPacketRecieved) {
+ radiusServerOperationalStatus = OperationalStatus.IN_USE;
+ } else if (statusServerReqSent && !fakeAccessRequestPacketRecieved) {
+ radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE;
+ } else {
+ radiusServerOperationalStatus = OperationalStatus.UNKNOWN;
+ }
+ } else {
+ radiusServerOperationalStatus = OperationalStatus.IN_USE;
+ }
+ }
+
+ public void checkServerOperationalStatus() {
+
+ try {
+ if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.STATUS_REQUEST) {
+ // determine operational status by statusServerRequest
+ checkServerStatusUsingStatusServerRequest();
+ if (statusServerReqSent && serverStatusPacketRecieved) {
+ // if req sent and response recieved
+ radiusServerOperationalStatus = OperationalStatus.IN_USE;
+ } else if (statusServerReqSent && !serverStatusPacketRecieved) {
+ radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE;
+ } else {
+ radiusServerOperationalStatus = OperationalStatus.UNKNOWN;
+ }
+ } else {
+ if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.AUTO) {
+ checkServerStatusUsingStatusServerRequest();
+ if (statusServerReqSent && serverStatusPacketRecieved) {
+ radiusServerOperationalStatus = OperationalStatus.IN_USE;
+ } else {
+ checkStatusServerForAccessRequestMode();
+ }
+ } else {
+ checkStatusServerForAccessRequestMode();
+ }
+ }
+ fakeAccessRequestPacketRecieved = false;
+ serverStatusPacketRecieved = false;
+ } catch (Exception e) {
+ log.error("Caught exception while checking radius server status::" + e);
+ }
+ }
+
+ /**
+ * Delegate allowing the RadiusOperationalStatus to notify us of events.
+ */
+ private class InternalRadiusOperationalStatusDelegate implements RadiusOperationalStatusEventDelegate {
+ @Override
+ public void notify(RadiusOperationalStatusEvent radiusOperationalStatusEvent) {
+ log.debug("Radius Operational Status event {} for {}", radiusOperationalStatusEvent.type(),
+ radiusOperationalStatusEvent.subject());
+ post(radiusOperationalStatusEvent);
+ }
+ }
+
+}
diff --git a/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java b/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
index 0324083..d3c49c2 100755
--- a/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
+++ b/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
@@ -15,18 +15,7 @@
*/
package org.opencord.aaa.impl;
-import static org.onosproject.net.packet.PacketPriority.CONTROL;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
@@ -41,7 +30,17 @@
import org.opencord.aaa.RadiusCommunicator;
import org.slf4j.Logger;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Handles Socket based communication with the RADIUS server.
@@ -148,10 +147,11 @@
log.trace("Sending packet {} to Radius Server {}:{} using socket",
radiusPacket, address, radiusServerPort);
}
- aaaManager.aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
socket.send(packet);
+ aaaManager.radiusOperationalStatusService.setStatusServerReqSent(true);
} catch (UnknownHostException uhe) {
log.warn("Unable to resolve host {}", radiusHost);
+ aaaManager.radiusOperationalStatusService.setStatusServerReqSent(false);
}
} catch (IOException e) {
log.info("Cannot send packet to RADIUS server", e);
diff --git a/app/src/main/java/org/opencord/aaa/impl/StateMachine.java b/app/src/main/java/org/opencord/aaa/impl/StateMachine.java
index 5e9e140..48e4ac0 100644
--- a/app/src/main/java/org/opencord/aaa/impl/StateMachine.java
+++ b/app/src/main/java/org/opencord/aaa/impl/StateMachine.java
@@ -17,19 +17,18 @@
package org.opencord.aaa.impl;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
+import com.google.common.collect.Maps;
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import org.opencord.aaa.AuthenticationEvent;
import org.opencord.aaa.StateMachineDelegate;
import org.slf4j.Logger;
-import com.google.common.collect.Maps;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
/**
* AAA Finite State Machine.
@@ -56,7 +55,7 @@
static final int TRANSITION_DENY_ACCESS = 3;
static final int TRANSITION_LOGOFF = 4;
- private static int identifier = -1;
+ private static int identifier = 1;
private byte challengeIdentifier;
private byte[] challengeState;
private byte[] username;
@@ -129,7 +128,7 @@
public static void initializeMaps() {
sessionIdMap = Maps.newConcurrentMap();
identifierMap = Maps.newConcurrentMap();
- identifier = -1;
+ identifier = 1;
}
public static void destroyMaps() {
@@ -207,7 +206,7 @@
if (e.getValue() != null && e.getValue().supplicantAddress != null
&& e.getValue().supplicantAddress.equals(mac)) {
sessionIdMap.remove(e.getValue().sessionId);
- if (e.getValue().identifier != -1) {
+ if (e.getValue().identifier != 1) {
deleteStateMachineMapping(e.getValue());
}
break;
@@ -419,9 +418,11 @@
* @return The state machine identifier.
*/
public synchronized byte identifier() {
- identifier = (identifier + 1) % 255;
- identifierMap.put(identifier, this);
- return (byte) identifier;
+ //identifier 0 is for statusServerrequest
+ //identifier 1 is for fake accessRequest
+ identifier = (identifier + 1) % 253;
+ identifierMap.put((identifier + 2), this);
+ return (byte) (identifier + 2);
}
/**
diff --git a/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java b/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
index 7303257..1b4257d 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
@@ -122,13 +122,13 @@
String challenge = "12345678901234567";
- EAP eap = new EAP(challengeType, (byte) 1, challengeType,
+ EAP eap = new EAP(challengeType, (byte) 4, challengeType,
challenge.getBytes(Charsets.US_ASCII));
- eap.setIdentifier((byte) 1);
+ eap.setIdentifier((byte) 4);
RADIUS radius = new RADIUS();
radius.setCode(challengeCode);
-
+ radius.setIdentifier((byte) 4);
radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
challenge.getBytes(Charsets.US_ASCII));
@@ -167,6 +167,7 @@
aaaManager.sadisService = new MockSadisService();
aaaManager.cfgService = new MockCfgService();
aaaStatisticsManager = new AaaStatisticsManager();
+ aaaManager.radiusOperationalStatusService = new RadiusOperationalStatusManager();
TestUtils.setField(aaaStatisticsManager, "eventDispatcher", new TestEventDispatcher());
aaaStatisticsManager.activate();
aaaManager.aaaStatisticsManager = this.aaaStatisticsManager;
@@ -228,7 +229,7 @@
// (2) Supplicant identify
- Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 1, null);
+ Ethernet identifyPacket = constructSupplicantIdentifyPacket(null, EAP.ATTR_IDENTITY, (byte) 3, null);
sendPacket(identifyPacket);
RADIUS radiusIdentifyPacket = (RADIUS) fetchPacket(1);
@@ -273,7 +274,7 @@
RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3);
checkRadiusPacketFromSupplicant(responseMd5RadiusPacket);
- assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 3));
+ assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 9));
assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
// State machine should be in pending state
diff --git a/app/src/test/java/org/opencord/aaa/impl/AaaStatisticsTest.java b/app/src/test/java/org/opencord/aaa/impl/AaaStatisticsTest.java
index e4718b7..8627d3c 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaStatisticsTest.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaStatisticsTest.java
@@ -138,20 +138,24 @@
*/
private RADIUS constructRadiusCodeAccessChallengePacket(byte challengeCode, byte challengeType) {
- String challenge = "12345678901234567";
- EAP eap = new EAP(challengeType, (byte) 1, challengeType, challenge.getBytes(Charsets.US_ASCII));
- eap.setIdentifier((byte) 1);
+ String challenge = "12345678901234567";
- RADIUS radius = new RADIUS();
- radius.setCode(challengeCode);
+ EAP eap = new EAP(challengeType, (byte) 4, challengeType,
+ challenge.getBytes(Charsets.US_ASCII));
+ eap.setIdentifier((byte) 4);
- radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE, challenge.getBytes(Charsets.US_ASCII));
+ RADIUS radius = new RADIUS();
+ radius.setCode(challengeCode);
+ radius.setIdentifier((byte) 4);
+ radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+ challenge.getBytes(Charsets.US_ASCII));
- radius.setPayload(eap);
- radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE, eap.serialize());
- radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH, aaaManager.radiusSecret.getBytes());
- return radius;
-
+ radius.setPayload(eap);
+ radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE,
+ eap.serialize());
+ radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH,
+ aaaManager.radiusSecret.getBytes());
+ return radius;
}
public static void injectEventDispatcher(Object manager, EventDeliveryService svc) {
@@ -174,6 +178,7 @@
@Before
public void setUp() {
aaaManager = new AaaManagerWithoutRadiusServer();
+ aaaManager.radiusOperationalStatusService = new RadiusOperationalStatusManager();
aaaManager.netCfgService = new TestNetworkConfigRegistry();
aaaManager.coreService = new CoreServiceAdapter();
aaaManager.packetService = new MockPacketService();
@@ -278,7 +283,7 @@
RADIUS responseMd5RadiusPacket = (RADIUS) fetchPacket(3);
checkRadiusPacketFromSupplicant(responseMd5RadiusPacket);
- assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 3));
+ assertThat(responseMd5RadiusPacket.getIdentifier(), is((byte) 9));
assertThat(responseMd5RadiusPacket.getCode(), is(RADIUS.RADIUS_CODE_ACCESS_REQUEST));
// State machine should be in pending state
diff --git a/app/src/test/java/org/opencord/aaa/impl/AaaTestBase.java b/app/src/test/java/org/opencord/aaa/impl/AaaTestBase.java
index 4912e4e..8f48ce4 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaTestBase.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaTestBase.java
@@ -411,7 +411,7 @@
eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
eth.setVlanID((short) 2);
- EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 2, EAPOL.EAPOL_START, null);
+ EAP eap = new EAP(EAPOL.EAPOL_START, (byte) 3, EAPOL.EAPOL_START, null);
// eapol header
EAPOL eapol = new EAPOL();