[SEBA-37] Added 11 Statistics counters for Accounting Server operations
Change-Id: I7dda193129e5dffe62907775aaf8dfdc5b3f1bf1
diff --git a/api/src/main/java/org/opencord/aaa/AaaConfig.java b/api/src/main/java/org/opencord/aaa/AaaConfig.java
index 3072ff5..2c4aa7b 100644
--- a/api/src/main/java/org/opencord/aaa/AaaConfig.java
+++ b/api/src/main/java/org/opencord/aaa/AaaConfig.java
@@ -85,7 +85,6 @@
// Packet Customizer Default value
protected static final String DEFAULT_PACKET_CUSTOMIZER = "default";
-
/**
* Gets the value of a string property, protecting for an empty
* JSON object.
diff --git a/api/src/main/java/org/opencord/aaa/AaaStatistics.java b/api/src/main/java/org/opencord/aaa/AaaStatistics.java
new file mode 100644
index 0000000..9764427
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/AaaStatistics.java
@@ -0,0 +1,156 @@
+/*
+ * 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 java.util.concurrent.atomic.AtomicLong;
+
+public class AaaStatistics {
+ //Number of access accept packets sent to the server
+ private AtomicLong acceptResponsesRx = new AtomicLong();
+ //Number of access reject packets sent to the server
+ private AtomicLong rejectResponsesRx = new AtomicLong();
+ //Number of access challenge packets sent to the server
+ private AtomicLong challengeResponsesRx = new AtomicLong();
+ //Number of access request packets sent to the server
+ private AtomicLong accessRequestsTx = new AtomicLong();
+ //Number of access request packets pending a response from the server
+ private AtomicLong pendingRequests = new AtomicLong();
+ //Number of packets of an unknown RADIUS type received from the accounting server
+ private AtomicLong unknownTypeRx = new AtomicLong();
+ //Number of access response packets received from the server with an invalid validator
+ private AtomicLong invalidValidatorsRx = new AtomicLong();
+ //Number of dropped packets received from the accounting server
+ private AtomicLong droppedResponsesRx = new AtomicLong();
+ //Number of malformed access response packets received from the server
+ private AtomicLong malformedResponsesRx = new AtomicLong();
+ //Number of packets received from an unknown server
+ private AtomicLong unknownServerRx = new AtomicLong();
+ //Roundtrip packet time to the accounting server
+ private AtomicLong requestRttMilis = new AtomicLong();
+ //Number of access request packets retransmitted to the server
+ private AtomicLong requestReTx = new AtomicLong();
+ //Number of sessions expired
+ private AtomicLong numberOfSessionsExpired = new AtomicLong();
+
+ public Long getRequestReTx() {
+ return requestReTx.get();
+ }
+
+ public void setRequestRttMilis(AtomicLong requestRttMilis) {
+ this.requestRttMilis = requestRttMilis;
+ }
+
+ public Long getUnknownServerRx() {
+ return unknownServerRx.get();
+ }
+
+ public Long getRequestRttMilis() {
+ return requestRttMilis.get();
+ }
+
+ public Long getMalformedResponsesRx() {
+ return malformedResponsesRx.get();
+ }
+
+ public Long getDroppedResponsesRx() {
+ return droppedResponsesRx.get();
+ }
+
+ public Long getInvalidValidatorsRx() {
+ return invalidValidatorsRx.get();
+ }
+
+ public Long getAcceptResponsesRx() {
+ return acceptResponsesRx.get();
+ }
+
+ public Long getRejectResponsesRx() {
+ return rejectResponsesRx.get();
+ }
+
+ public Long getChallengeResponsesRx() {
+ return challengeResponsesRx.get();
+ }
+
+ public Long getAccessRequestsTx() {
+ return accessRequestsTx.get();
+ }
+
+ public Long getPendingRequests() {
+ return pendingRequests.get();
+ }
+
+ public Long getUnknownTypeRx() {
+ return unknownTypeRx.get();
+ }
+
+ public void increaseAcceptResponsesRx() {
+ acceptResponsesRx.incrementAndGet();
+ }
+
+ public void increaseRejectResponsesRx() {
+ rejectResponsesRx.incrementAndGet();
+ }
+
+ public void increaseChallengeResponsesRx() {
+ challengeResponsesRx.incrementAndGet();
+ }
+
+ public void increaseAccessRequestsTx() {
+ accessRequestsTx.incrementAndGet();
+ }
+
+ public void increaseRequestReTx() {
+ requestReTx.incrementAndGet();
+ }
+
+ public void increaseOrDecreasePendingRequests(boolean isIncrement) {
+ if (isIncrement) {
+ pendingRequests.incrementAndGet();
+ } else {
+ pendingRequests.decrementAndGet();
+ }
+ }
+
+ public void increaseUnknownTypeRx() {
+ unknownTypeRx.incrementAndGet();
+ }
+
+ public void increaseMalformedResponsesRx() {
+ malformedResponsesRx.incrementAndGet();
+ }
+
+ public void increaseInvalidValidatorsRx() {
+ invalidValidatorsRx.incrementAndGet();
+ }
+
+ public void incrementUnknownServerRx() {
+ unknownServerRx.incrementAndGet();
+ }
+
+ public void incrementNumberOfSessionsExpired() {
+ numberOfSessionsExpired.incrementAndGet();
+ }
+
+ public void countDroppedResponsesRx() {
+ long numberOfDroppedPackets = invalidValidatorsRx.get();
+ numberOfDroppedPackets += unknownTypeRx.get();
+ numberOfDroppedPackets += malformedResponsesRx.get();
+ numberOfDroppedPackets += numberOfSessionsExpired.get();
+ this.droppedResponsesRx = new AtomicLong(numberOfDroppedPackets);
+ }
+}
diff --git a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsDelegate.java b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsDelegate.java
new file mode 100644
index 0000000..b82e82f
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsDelegate.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+
+/**
+ * Delegate for Authentication Statistics.
+ */
+
+public interface AuthenticationStatisticsDelegate extends StoreDelegate<AuthenticationStatisticsEvent> {
+}
diff --git a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java
new file mode 100644
index 0000000..11c00e3
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+/**
+ * Event indicating the Accounting Data of AAA.
+ */
+public class AuthenticationStatisticsEvent extends
+ AbstractEvent<AuthenticationStatisticsEvent.Type, AaaStatistics> {
+/**
+ * Accounting data.
+ * AuthenticationMetrixEvent event type.
+ */
+ public enum Type {
+ /**
+ * signifies that the Authentication Metrix Event stats has been updated.
+ */
+ STATS_UPDATE
+ }
+ public AuthenticationStatisticsEvent(Type type, AaaStatistics stats) {
+ super(type, stats);
+ }
+}
diff --git a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEventListener.java b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEventListener.java
new file mode 100644
index 0000000..5cef070
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEventListener.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Listener for accounting events.
+ */
+public interface AuthenticationStatisticsEventListener extends
+ EventListener<AuthenticationStatisticsEvent> {
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java
new file mode 100644
index 0000000..bdb9f2d
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java
@@ -0,0 +1,60 @@
+/*
+ * 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.ListenerService;
+
+/**
+ * Service for interacting with accounting module.
+ */
+
+public interface AuthenticationStatisticsService extends
+ ListenerService<AuthenticationStatisticsEvent, AuthenticationStatisticsEventListener> {
+
+ /**
+ * Returns AaaStatistics object.
+ *
+ * @return AaaStatistics
+ */
+ public AaaStatistics getAaaStats();
+
+ /**
+ * Returns AuthenticationStatisticsDelegate object.
+ *
+ * @return AuthenticationStatisticsDelegate
+ */
+ public AuthenticationStatisticsDelegate getStatsDelegate();
+
+ /**
+ * Handle the roundTrip time of Radius Packet.
+ *
+ * @param identifier identifier of incoming radius packet
+ */
+ public void handleRoundtripTime(byte identifier);
+
+ /**
+ * Calculate average roundTrip time of multiple Packets.
+ */
+ public void calculatePacketRoundtripTime();
+
+ /**
+ * Put the identifier value to map.
+ *
+ * @param identifier identifier of incoming radius packet
+ */
+ public void putOutgoingIdentifierToMap(byte identifier);
+}
diff --git a/app/pom.xml b/app/pom.xml
index 0a191db..4362b36 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -72,9 +72,18 @@
<groupId>org.onosproject</groupId>
<artifactId>onos-maven-plugin</artifactId>
<version>1.11</version>
+ <executions>
+ <execution>
+ <id>cfg</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>cfg</goal>
+ </goals>
+ </execution>
+ </executions>
</plugin>
</plugins>
</build>
-</project>
\ No newline at end of file
+</project>
diff --git a/app/src/main/java/org/opencord/aaa/impl/AaaManager.java b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
index 3e75f17..bcd4cfa 100755
--- a/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
+++ b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
@@ -19,12 +19,16 @@
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 org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
@@ -36,6 +40,8 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.event.AbstractListenerManager;
@@ -62,14 +68,23 @@
import org.opencord.aaa.AuthenticationEvent;
import org.opencord.aaa.AuthenticationEventListener;
import org.opencord.aaa.AuthenticationService;
+import org.opencord.aaa.AuthenticationStatisticsEvent;
+import org.opencord.aaa.AuthenticationStatisticsService;
import org.opencord.aaa.RadiusCommunicator;
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.slf4j.Logger;
+import com.google.common.base.Strings;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
/**
* AAA application for ONOS.
*/
@@ -101,10 +116,21 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected MastershipService mastershipService;
- protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected AuthenticationStatisticsService aaaStatisticsManager;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService cfgService;
+
+ protected AuthenticationStatisticsEventPublisher authenticationStatisticsPublisher;
+ protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
private final DeviceListener deviceListener = new InternalDeviceListener();
+ private static final int DEFAULT_REPEAT_DELAY = 20;
+ @Property(name = "statisticsGenerationEvent", intValue = DEFAULT_REPEAT_DELAY,
+ label = "statisticsGenerationEvent")
+ private int statisticsGenerationEvent = DEFAULT_REPEAT_DELAY;
+
// NAS IP address
protected InetAddress nasIpAddress;
@@ -146,6 +172,11 @@
// latest configuration
AaaConfig newCfg;
+ ScheduledFuture<?> scheduledFuture;
+
+ ScheduledExecutorService executor;
+ String configuredAaaServerAddress;
+ HashSet<Byte> outPacketSet = new HashSet<Byte>();
// Configuration properties factory
private final ConfigFactory factory =
new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
@@ -197,48 +228,58 @@
}
@Activate
- public void activate() {
+ public void activate(ComponentContext context) {
appId = coreService.registerApplication(APP_NAME);
eventDispatcher.addSink(AuthenticationEvent.class, listenerRegistry);
netCfgService.addListener(cfgListener);
netCfgService.registerConfigFactory(factory);
+ cfgService.registerProperties(getClass());
+ modified(context);
subsService = sadisService.getSubscriberInfoService();
customInfo = new CustomizationInfo(subsService, deviceService);
cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
log.info("Starting with config {} {}", this, newCfg);
-
configureRadiusCommunication();
-
// register our event handler
packetService.addProcessor(processor, PacketProcessor.director(2));
-
-
StateMachine.initializeMaps();
StateMachine.setDelegate(delegate);
-
impl.initializeLocalState(newCfg);
-
impl.requestIntercepts();
-
deviceService.addListener(deviceListener);
+ getConfiguredAaaServerAddress();
+ authenticationStatisticsPublisher =
+ new AuthenticationStatisticsEventPublisher();
+ executor = Executors.newScheduledThreadPool(1);
+ scheduledFuture = executor.scheduleAtFixedRate(authenticationStatisticsPublisher,
+ 0, statisticsGenerationEvent, TimeUnit.SECONDS);
log.info("Started");
}
-
@Deactivate
- public void deactivate() {
+ public void deactivate(ComponentContext context) {
impl.withdrawIntercepts();
packetService.removeProcessor(processor);
netCfgService.removeListener(cfgListener);
+ cfgService.unregisterProperties(getClass(), false);
StateMachine.unsetDelegate(delegate);
StateMachine.destroyMaps();
impl.deactivate();
deviceService.removeListener(deviceListener);
eventDispatcher.removeSink(AuthenticationEvent.class);
+ scheduledFuture.cancel(true);
+ executor.shutdown();
log.info("Stopped");
}
+ @Modified
+ public void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ String s = Tools.get(properties, "statisticsGenerationEvent");
+ statisticsGenerationEvent = Strings.isNullOrEmpty(s) ? DEFAULT_REPEAT_DELAY : Integer.parseInt(s.trim());
+ }
+
private void configureRadiusCommunication() {
if (radiusConnectionType.toLowerCase().equals("socket")) {
impl = new SocketBasedRadiusCommunicator(appId, packetService, this);
@@ -265,6 +306,32 @@
}
}
+ private void getConfiguredAaaServerAddress() {
+ try {
+ InetAddress address;
+ if (newCfg.radiusHostName() != null) {
+ address = InetAddress.getByName(newCfg.radiusHostName());
+ } else {
+ address = newCfg.radiusIp();
+ }
+
+ configuredAaaServerAddress = address.getHostAddress();
+ } catch (UnknownHostException uhe) {
+ log.warn("Unable to resolve host {}", newCfg.radiusHostName());
+ }
+ }
+
+ private void checkReceivedPacketForValidValidator(RADIUS radiusPacket) {
+ if (!radiusPacket.checkMessageAuthenticator(radiusSecret)) {
+ aaaStatisticsManager.getAaaStats().increaseInvalidValidatorsRx();
+ }
+ }
+ public void checkForPacketFromUnknownServer(String hostAddress) {
+ if (!hostAddress.equals(configuredAaaServerAddress)) {
+ aaaStatisticsManager.getAaaStats().incrementUnknownServerRx();
+ }
+ }
+
/**
* Send RADIUS packet to the RADIUS server.
*
@@ -272,6 +339,9 @@
* @param inPkt Incoming EAPOL packet
*/
protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
+ outPacketSet.add(radiusPacket.getIdentifier());
+ aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(true);
+ aaaStatisticsManager.getAaaStats().increaseAccessRequestsTx();
impl.sendRadiusPacket(radiusPacket, inPkt);
}
@@ -291,12 +361,17 @@
if (stateMachine == null) {
log.error("Invalid packet identifier {}, could not find corresponding "
+ "state machine ... exiting", radiusPacket.getIdentifier());
+ aaaStatisticsManager.getAaaStats().incrementNumberOfSessionsExpired();
+ aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
return;
}
-
EAP eapPayload;
Ethernet eth;
-
+ checkReceivedPacketForValidValidator(radiusPacket);
+ if (outPacketSet.contains(radiusPacket.getIdentifier())) {
+ aaaStatisticsManager.getAaaStats().increaseOrDecreasePendingRequests(false);
+ outPacketSet.remove(new Byte(radiusPacket.getIdentifier()));
+ }
switch (radiusPacket.getCode()) {
case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
log.debug("RADIUS packet: RADIUS_CODE_ACCESS_CHALLENGE");
@@ -314,6 +389,7 @@
eapPayload, stateMachine.priorityCode());
log.debug("Send EAP challenge response to supplicant {}", stateMachine.supplicantAddress().toString());
sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+ aaaStatisticsManager.getAaaStats().increaseChallengeResponsesRx();
break;
case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
log.debug("RADIUS packet: RADIUS_CODE_ACCESS_ACCEPT");
@@ -331,7 +407,7 @@
sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
stateMachine.authorizeAccess();
-
+ aaaStatisticsManager.getAaaStats().increaseAcceptResponsesRx();
break;
case RADIUS.RADIUS_CODE_ACCESS_REJECT:
log.debug("RADIUS packet: RADIUS_CODE_ACCESS_REJECT");
@@ -356,11 +432,13 @@
log.warn("Send EAP failure message to supplicant {}", stateMachine.supplicantAddress().toString());
sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
stateMachine.denyAccess();
-
+ aaaStatisticsManager.getAaaStats().increaseRejectResponsesRx();
break;
default:
log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
+ aaaStatisticsManager.getAaaStats().increaseUnknownTypeRx();
}
+ aaaStatisticsManager.getAaaStats().countDroppedResponsesRx();
}
/**
@@ -473,7 +551,6 @@
log.debug("Using existing state-machine for sessionId: {}", sessionId);
}
-
switch (eapol.getEapolType()) {
case EAPOL.EAPOL_START:
log.debug("EAP packet: EAPOL_START");
@@ -523,6 +600,9 @@
sendRadiusPacket(radiusPayload, inPacket);
// change the state to "PENDING"
+ if (stateMachine.state() == StateMachine.STATE_PENDING) {
+ aaaStatisticsManager.getAaaStats().increaseRequestReTx();
+ }
stateMachine.requestAccess();
break;
case EAP.ATTR_MD5:
@@ -686,4 +766,26 @@
}
}
}
+ private class AuthenticationStatisticsEventPublisher implements Runnable {
+ private final Logger log = getLogger(getClass());
+ public void run() {
+ log.info("Notifying AuthenticationStatisticsEvent");
+ aaaStatisticsManager.calculatePacketRoundtripTime();
+ log.debug("AcceptResponsesRx---" + aaaStatisticsManager.getAaaStats().getAcceptResponsesRx());
+ log.debug("AccessRequestsTx---" + aaaStatisticsManager.getAaaStats().getAccessRequestsTx());
+ log.debug("ChallengeResponsesRx---" + aaaStatisticsManager.getAaaStats().getChallengeResponsesRx());
+ log.debug("DroppedResponsesRx---" + aaaStatisticsManager.getAaaStats().getDroppedResponsesRx());
+ log.debug("InvalidValidatorsRx---" + aaaStatisticsManager.getAaaStats().getInvalidValidatorsRx());
+ log.debug("MalformedResponsesRx---" + aaaStatisticsManager.getAaaStats().getMalformedResponsesRx());
+ log.debug("PendingRequests---" + aaaStatisticsManager.getAaaStats().getPendingRequests());
+ log.debug("RejectResponsesRx---" + aaaStatisticsManager.getAaaStats().getRejectResponsesRx());
+ log.debug("RequestReTx---" + aaaStatisticsManager.getAaaStats().getRequestReTx());
+ log.debug("RequestRttMilis---" + aaaStatisticsManager.getAaaStats().getRequestRttMilis());
+ log.debug("UnknownServerRx---" + aaaStatisticsManager.getAaaStats().getUnknownServerRx());
+ log.debug("UnknownTypeRx---" + aaaStatisticsManager.getAaaStats().getUnknownTypeRx());
+ aaaStatisticsManager.getStatsDelegate().
+ notify(new AuthenticationStatisticsEvent(AuthenticationStatisticsEvent.Type.STATS_UPDATE,
+ aaaStatisticsManager.getAaaStats()));
+ }
+ }
}
diff --git a/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java b/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java
new file mode 100644
index 0000000..89be1fe
--- /dev/null
+++ b/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java
@@ -0,0 +1,106 @@
+/*
+ * 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.impl;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.event.AbstractListenerManager;
+import org.opencord.aaa.AaaStatistics;
+import org.opencord.aaa.AuthenticationStatisticsDelegate;
+import org.opencord.aaa.AuthenticationStatisticsEvent;
+import org.opencord.aaa.AuthenticationStatisticsEventListener;
+import org.opencord.aaa.AuthenticationStatisticsService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Deactivate;
+import org.slf4j.Logger;
+
+
+@Service
+@Component(immediate = true)
+public class AaaStatisticsManager
+ extends AbstractListenerManager<AuthenticationStatisticsEvent, AuthenticationStatisticsEventListener>
+ implements AuthenticationStatisticsService {
+
+ private AuthenticationStatisticsDelegate statsDelegate;
+
+ public AuthenticationStatisticsDelegate getStatsDelegate() {
+ return statsDelegate;
+ }
+
+ private final Logger log = getLogger(getClass());
+ private AaaStatistics aaaStats;
+ private LinkedList<Long> packetRoundTripTimeList = new LinkedList<Long>();
+ public Map<Byte, Long> outgoingPacketMap = new HashMap<Byte, Long>();
+ private static final int PACKET_COUNT_FOR_AVERAGE_RTT_CALCULATION = 5;
+
+ public AaaStatistics getAaaStats() {
+ return aaaStats;
+ }
+
+ @Activate
+ public void activate() {
+ log.info("Activate aaaStatisticsManager");
+ aaaStats = new AaaStatistics();
+ statsDelegate = new InternalAuthenticationDelegateForStatistics();
+ eventDispatcher.addSink(AuthenticationStatisticsEvent.class, listenerRegistry);
+ }
+
+ @Deactivate
+ public void deactivate() {
+ eventDispatcher.removeSink(AuthenticationStatisticsEvent.class);
+ }
+
+ public void handleRoundtripTime(byte inPacketIdentifier) {
+ long inTimeInMilis = System.currentTimeMillis();
+ if (outgoingPacketMap.containsKey(inPacketIdentifier)) {
+ if (packetRoundTripTimeList.size() > PACKET_COUNT_FOR_AVERAGE_RTT_CALCULATION) {
+ packetRoundTripTimeList.removeFirst();
+ }
+ packetRoundTripTimeList.add(inTimeInMilis - outgoingPacketMap.get(inPacketIdentifier));
+ }
+ }
+
+ public void calculatePacketRoundtripTime() {
+ if (packetRoundTripTimeList.size() > 0) {
+ long avg = (long) packetRoundTripTimeList.stream().mapToLong(i -> i).average().getAsDouble();
+ aaaStats.setRequestRttMilis(new AtomicLong(avg));
+ }
+ }
+
+ public void putOutgoingIdentifierToMap(byte outPacketIdentifier) {
+ outgoingPacketMap.put(outPacketIdentifier, System.currentTimeMillis());
+ }
+
+ /**
+ *Delegate allowing the StateMachine to notify us of events.
+ */
+ private class InternalAuthenticationDelegateForStatistics implements AuthenticationStatisticsDelegate {
+ @Override
+ public void notify(AuthenticationStatisticsEvent authenticationStatisticsEvent) {
+ log.debug("Authentication Statistics event {} for {}", authenticationStatisticsEvent.type(),
+ authenticationStatisticsEvent.subject());
+ post(authenticationStatisticsEvent);
+ }
+ }
+}
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 e1b8bb9..2967a14 100755
--- a/app/src/main/java/org/opencord/aaa/impl/PortBasedRadiusCommunicator.java
+++ b/app/src/main/java/org/opencord/aaa/impl/PortBasedRadiusCommunicator.java
@@ -109,7 +109,6 @@
PacketCustomizer pktCustomizer;
AaaManager aaaManager;
-
ConnectPoint radiusServerConnectPoint = null;
InnerMastershipListener changeListener = new InnerMastershipListener();
@@ -264,7 +263,7 @@
return;
}
ipToSnMap.put(deviceInfo.ipAddress(), serialNo);
-
+ aaaManager.aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
// send the message out
sendFromRadiusServerPort(pktCustomizer.
customizeEthernetIPHeaders(ethReply, inPkt));
@@ -390,6 +389,7 @@
8,
udpPacket.getLength() - 8);
try {
+ aaaManager.aaaStatisticsManager.handleRoundtripTime(radiusMsg.getIdentifier());
aaaManager.handleRadiusPacket(radiusMsg);
} catch (StateMachineException sme) {
log.error("Illegal state machine operation", sme);
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 e2bce35..0324083 100755
--- a/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
+++ b/app/src/main/java/org/opencord/aaa/impl/SocketBasedRadiusCommunicator.java
@@ -148,6 +148,7 @@
log.trace("Sending packet {} to Radius Server {}:{} using socket",
radiusPacket, address, radiusServerPort);
}
+ aaaManager.aaaStatisticsManager.putOutgoingIdentifierToMap(radiusPacket.getIdentifier());
socket.send(packet);
} catch (UnknownHostException uhe) {
log.warn("Unable to resolve host {}", radiusHost);
@@ -184,6 +185,7 @@
new DatagramPacket(packetBuffer, packetBuffer.length);
DatagramSocket socket = radiusSocket;
socket.receive(inboundBasePacket);
+ aaaManager.checkForPacketFromUnknownServer(inboundBasePacket.getAddress().getHostAddress());
log.debug("Packet #{} received", packetNumber++);
try {
inboundRadiusPacket =
@@ -191,8 +193,10 @@
.deserialize(inboundBasePacket.getData(),
0,
inboundBasePacket.getLength());
+ aaaManager.aaaStatisticsManager.handleRoundtripTime(inboundRadiusPacket.getIdentifier());
aaaManager.handleRadiusPacket(inboundRadiusPacket);
} catch (DeserializationException dex) {
+ aaaManager.aaaStatisticsManager.getAaaStats().increaseMalformedResponsesRx();
log.error("Cannot deserialize packet", dex);
} catch (StateMachineException sme) {
log.error("Illegal state machine operation", sme);
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 f9e5f25..0b60c2e 100644
--- a/app/src/main/java/org/opencord/aaa/impl/StateMachine.java
+++ b/app/src/main/java/org/opencord/aaa/impl/StateMachine.java
@@ -63,7 +63,6 @@
private final Logger log = getLogger(getClass());
-
private State[] states = {
new Idle(), new Started(), new Pending(), new Authorized(), new Unauthorized()
};
diff --git a/app/src/test/java/org/opencord/aaa/impl/AaaIntegrationTest.java b/app/src/test/java/org/opencord/aaa/impl/AaaIntegrationTest.java
index 8ded2f8..0275b13 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaIntegrationTest.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaIntegrationTest.java
@@ -25,6 +25,7 @@
import org.onosproject.net.config.Config;
import org.onosproject.net.config.NetworkConfigRegistryAdapter;
import org.opencord.aaa.AaaConfig;
+import org.opencord.aaa.impl.AaaTestBase.MockCfgService;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@@ -60,7 +61,8 @@
aaa.netCfgService = new TestNetworkConfigRegistry();
aaa.coreService = new CoreServiceAdapter();
aaa.packetService = new MockPacketService();
- aaa.activate();
+ aaa.cfgService = new MockCfgService();
+ aaa.activate(new AaaTestBase.MockComponentContext());
}
/**
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 8827c1a..7303257 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
@@ -54,13 +54,13 @@
static final String BAD_IP_ADDRESS = "198.51.100.0";
private AaaManager aaaManager;
+ private AaaStatisticsManager aaaStatisticsManager;
class AaaManagerWithoutRadiusServer extends AaaManager {
protected void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
savePacket(radiusPacket);
}
}
-
/**
* Mocks the AAAConfig class to force usage of an unroutable address for the
* RADIUS server.
@@ -92,7 +92,6 @@
public static class TestEventDispatcher extends DefaultEventSinkRegistry
implements EventDeliveryService {
-
@Override
@SuppressWarnings("unchecked")
public synchronized void post(Event event) {
@@ -136,7 +135,8 @@
radius.setPayload(eap);
radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE,
eap.serialize());
-
+ radius.setAttribute(RADIUSAttribute.RADIUS_ATTR_MESSAGE_AUTH,
+ aaaManager.radiusSecret.getBytes());
return radius;
}
@@ -165,8 +165,13 @@
aaaManager.packetService = new MockPacketService();
aaaManager.deviceService = new TestDeviceService();
aaaManager.sadisService = new MockSadisService();
+ aaaManager.cfgService = new MockCfgService();
+ aaaStatisticsManager = new AaaStatisticsManager();
+ TestUtils.setField(aaaStatisticsManager, "eventDispatcher", new TestEventDispatcher());
+ aaaStatisticsManager.activate();
+ aaaManager.aaaStatisticsManager = this.aaaStatisticsManager;
TestUtils.setField(aaaManager, "eventDispatcher", new TestEventDispatcher());
- aaaManager.activate();
+ aaaManager.activate(new AaaTestBase.MockComponentContext());
}
/**
@@ -174,7 +179,7 @@
*/
@After
public void tearDown() {
- aaaManager.deactivate();
+ aaaManager.deactivate(new AaaTestBase.MockComponentContext());
}
/**
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 2e21ea3..b49fbc4 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaTestBase.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaTestBase.java
@@ -23,7 +23,8 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
-
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cfg.ConfigProperty;
import org.onosproject.net.Annotations;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.ConnectPoint;
@@ -42,9 +43,16 @@
import org.opencord.sadis.BaseInformationService;
import org.opencord.sadis.SadisService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
+import java.util.Dictionary;
+import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -100,6 +108,67 @@
}
}
}
+ class MockComponentContext implements ComponentContext {
+
+ @Override
+ public Dictionary<String, Object> getProperties() {
+ Dictionary<String, Object> cfgDict = new Hashtable<String, Object>();
+ cfgDict.put("statisticsGenerationEvent", 20);
+ return cfgDict;
+ }
+
+ @Override
+ public Object locateService(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object locateService(String name, ServiceReference reference) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Object[] locateServices(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BundleContext getBundleContext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Bundle getUsingBundle() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ComponentInstance getComponentInstance() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void enableComponent(String name) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void disableComponent(String name) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public ServiceReference getServiceReference() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ }
/**
* Mocks the DeviceService.
@@ -173,6 +242,55 @@
}
}
+ final class MockCfgService implements ComponentConfigService {
+ @Override
+ public Set<String> getComponentNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void registerProperties(Class<?> componentClass) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void unregisterProperties(Class<?> componentClass, boolean clear) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public Set<ConfigProperty> getProperties(String componentName) {
+ return null;
+ }
+
+ @Override
+ public void setProperty(String componentName, String name, String value) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void preSetProperty(String componentName, String name, String value) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void preSetProperty(String componentName, String name, String value, boolean override) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void unsetProperty(String componentName, String name) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public ConfigProperty getProperty(String componentName, String attribute) {
+ return null;
+ }
+
+}
+
final class MockSubService implements BaseInformationService<SubscriberAndDeviceInformation> {
private final VlanId clientCtag = VlanId.vlanId((short) 999);
private final VlanId clientStag = VlanId.vlanId((short) 111);