Publish cluster-wide AAA stats
Change-Id: Icbdacdae08b6235be022f85eb41ce6d0f8f35a35
diff --git a/api/src/main/java/org/opencord/aaa/AaaStatistics.java b/api/src/main/java/org/opencord/aaa/AaaStatistics.java
index c9953e3..436979e 100644
--- a/api/src/main/java/org/opencord/aaa/AaaStatistics.java
+++ b/api/src/main/java/org/opencord/aaa/AaaStatistics.java
@@ -16,10 +16,84 @@
package org.opencord.aaa;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicLong;
+/**
+ * Records metrics for the AAA application.
+ */
public class AaaStatistics {
+ public static final String ACCEPT_RESPONSES_RX = "acceptResponsesRx";
+ public static final String REJECT_RESPONSES_RX = "rejectResponsesRx";
+ public static final String CHALLENGE_RESPONSES_RX = "challengeResponsesRx";
+ public static final String ACCESS_REQUESTS_TX = "accessRequestsTx";
+ public static final String PENDING_REQUESTS = "pendingRequests";
+ public static final String TIMED_OUT_PACKETS = "timedOutPackets";
+ public static final String UNKNOWN_TYPE_RX = "unknownTypeRx";
+ public static final String INVALID_VALIDATORS_RX = "invalidValidatorsRx";
+ public static final String DROPPED_RESPONSES_RX = "droppedResponsesRx";
+ public static final String MALFORMED_RESPONSES_RX = "malformedResponsesRx";
+ public static final String UNKNOWN_SERVER_RX = "unknownServerRx";
+ public static final String REQUEST_RTT_MILLIS = "requestRttMillis";
+ public static final String REQUEST_RE_TX = "requestReTx";
+ public static final String NUM_SESSIONS_EXPIRED = "numSessionsExpired";
+ public static final String EAPOL_LOGOFF_RX = "eapolLogoffRx";
+ public static final String EAPOL_AUTH_SUCCESS_TRANS = "eapolAuthSuccessTrans";
+ public static final String EAPOL_AUTH_FAILURE_TRANS = "eapolAuthFailureTrans";
+ public static final String EAPOL_START_REQ_TRANS = "eapolStartReqTrans";
+ public static final String EAPOL_MD5_RESP_CHALLENGE = "eapolMd5RespChallenge";
+ public static final String EAPOL_TLS_RESP_CHALLENGE = "eapolTlsRespChallenge";
+ public static final String EAPOL_TRANS_RESP_NOT_NAK = "eapolTransRespNotNak";
+ public static final String EAP_PKT_TX_AUTH_CHOOSE_EAP = "eapPktTxauthChooseEap";
+ public static final String RES_ID_EAP_FRAMES_RX = "resIdEapFramesRx";
+ public static final String EAPOL_RES_IDENTITY_MSG_TRANS = "eapolResIdentityMsgTrans";
+ public static final String EAPOL_FRAMES_TX = "eapolFramesTx";
+ public static final String AUTH_STATE_IDLE = "authStateIdle";
+ public static final String REQUEST_ID_FRAMES_TX = "requestIdFramesTx";
+ public static final String REQUEST_EAP_FRAMES_TX = "requestEapFramesTx";
+ public static final String INVALID_PKT_TYPE = "invalidPktType";
+ public static final String INVALID_BODY_LENGTH = "invalidBodyLength";
+ public static final String VALID_EAPOL_FRAMES_RX = "validEapolFramesRx";
+ public static final String PENDING_RES_SUPPLICANT = "pendingResSupplicant";
+
+ public static final String[] COUNTER_NAMES = new String[]{
+ ACCEPT_RESPONSES_RX,
+ REJECT_RESPONSES_RX,
+ CHALLENGE_RESPONSES_RX,
+ ACCESS_REQUESTS_TX,
+ PENDING_REQUESTS,
+ TIMED_OUT_PACKETS,
+ UNKNOWN_TYPE_RX,
+ INVALID_VALIDATORS_RX,
+ DROPPED_RESPONSES_RX,
+ MALFORMED_RESPONSES_RX,
+ UNKNOWN_SERVER_RX,
+ REQUEST_RTT_MILLIS,
+ REQUEST_RE_TX,
+ NUM_SESSIONS_EXPIRED,
+ EAPOL_LOGOFF_RX,
+ EAPOL_AUTH_SUCCESS_TRANS,
+ EAPOL_AUTH_FAILURE_TRANS,
+ EAPOL_START_REQ_TRANS,
+ EAPOL_MD5_RESP_CHALLENGE,
+ EAPOL_TLS_RESP_CHALLENGE,
+ EAPOL_TRANS_RESP_NOT_NAK,
+ EAP_PKT_TX_AUTH_CHOOSE_EAP,
+ RES_ID_EAP_FRAMES_RX,
+ EAPOL_RES_IDENTITY_MSG_TRANS,
+ EAPOL_FRAMES_TX,
+ AUTH_STATE_IDLE,
+ REQUEST_ID_FRAMES_TX,
+ REQUEST_EAP_FRAMES_TX,
+ INVALID_PKT_TYPE,
+ INVALID_BODY_LENGTH,
+ VALID_EAPOL_FRAMES_RX,
+ PENDING_RES_SUPPLICANT,
+ };
+
// Number of access accept packets sent to the server
private AtomicLong acceptResponsesRx = new AtomicLong();
// Number of access reject packets sent to the server
@@ -386,8 +460,11 @@
validEapolFramesRx.set(0);
pendingResSupp.set(0);
timedOutPackets.set(0);
-
+ eapolMd5RspChall.set(0);
+ eapolTlsRespChall.set(0);
+ eapolAttrIdentity.set(0);
}
+
public void countTransRespNotNak() {
long eapolTransactionNotNak = eapolMd5RspChall.get();
eapolTransactionNotNak += eapolTlsRespChall.get();
@@ -413,4 +490,123 @@
timedOutPackets.incrementAndGet();
}
+ /**
+ * Creates a snapshot of the current values of the counters.
+ *
+ * @return statistics snapshot
+ */
+ public AaaStatisticsSnapshot snapshot() {
+ ImmutableMap.Builder<String, Long> builder = ImmutableMap.builder();
+ builder.put(ACCEPT_RESPONSES_RX, acceptResponsesRx.get())
+ .put(REJECT_RESPONSES_RX, rejectResponsesRx.get())
+ .put(CHALLENGE_RESPONSES_RX, challengeResponsesRx.get())
+ .put(ACCESS_REQUESTS_TX, accessRequestsTx.get())
+ .put(PENDING_REQUESTS, pendingRequests.get())
+ .put(TIMED_OUT_PACKETS, timedOutPackets.get())
+ .put(UNKNOWN_TYPE_RX, unknownTypeRx.get())
+ .put(INVALID_VALIDATORS_RX, invalidValidatorsRx.get())
+ .put(DROPPED_RESPONSES_RX, droppedResponsesRx.get())
+ .put(MALFORMED_RESPONSES_RX, malformedResponsesRx.get())
+ .put(UNKNOWN_SERVER_RX, unknownServerRx.get())
+ .put(REQUEST_RTT_MILLIS, requestRttMilis.get())
+ .put(REQUEST_RE_TX, requestReTx.get())
+ .put(NUM_SESSIONS_EXPIRED, numberOfSessionsExpired.get())
+ .put(EAPOL_LOGOFF_RX, eapolLogoffRx.get())
+ .put(EAPOL_AUTH_SUCCESS_TRANS, eapolAuthSuccessTrans.get())
+ .put(EAPOL_AUTH_FAILURE_TRANS, eapolAuthFailureTrans.get())
+ .put(EAPOL_START_REQ_TRANS, eapolStartReqTrans.get())
+ .put(EAPOL_MD5_RESP_CHALLENGE, eapolMd5RspChall.get())
+ .put(EAPOL_TLS_RESP_CHALLENGE, eapolTlsRespChall.get())
+ .put(EAPOL_TRANS_RESP_NOT_NAK, eapolTransRespNotNak.get())
+ .put(EAP_PKT_TX_AUTH_CHOOSE_EAP, eapPktTxauthChooseEap.get())
+ .put(RES_ID_EAP_FRAMES_RX, eapolAttrIdentity.get())
+ .put(EAPOL_RES_IDENTITY_MSG_TRANS, eapolResIdentityMsgTrans.get())
+ .put(EAPOL_FRAMES_TX, eapolFramesTx.get())
+ .put(AUTH_STATE_IDLE, authStateIdle.get())
+ .put(REQUEST_ID_FRAMES_TX, requestIdFramesTx.get())
+ .put(REQUEST_EAP_FRAMES_TX, reqEapFramesTx.get())
+ .put(INVALID_PKT_TYPE, invalidPktType.get())
+ .put(INVALID_BODY_LENGTH, invalidBodyLength.get())
+ .put(VALID_EAPOL_FRAMES_RX, validEapolFramesRx.get())
+ .put(PENDING_RES_SUPPLICANT, pendingResSupp.get());
+
+ return new AaaStatisticsSnapshot(builder.build());
+ }
+
+ public static AaaStatistics fromSnapshot(AaaStatisticsSnapshot snapshot) {
+ AaaStatistics stats = new AaaStatistics();
+
+ stats.acceptResponsesRx.set(snapshot.get(ACCEPT_RESPONSES_RX));
+ stats.rejectResponsesRx.set(snapshot.get(REJECT_RESPONSES_RX));
+ stats.challengeResponsesRx.set(snapshot.get(CHALLENGE_RESPONSES_RX));
+ stats.accessRequestsTx.set(snapshot.get(ACCESS_REQUESTS_TX));
+ stats.pendingRequests.set(snapshot.get(PENDING_REQUESTS));
+ stats.timedOutPackets.set(snapshot.get(TIMED_OUT_PACKETS));
+ stats.unknownTypeRx.set(snapshot.get(UNKNOWN_TYPE_RX));
+ stats.invalidValidatorsRx.set(snapshot.get(INVALID_VALIDATORS_RX));
+ stats.droppedResponsesRx.set(snapshot.get(DROPPED_RESPONSES_RX));
+ stats.malformedResponsesRx.set(snapshot.get(MALFORMED_RESPONSES_RX));
+ stats.unknownServerRx.set(snapshot.get(UNKNOWN_SERVER_RX));
+ stats.requestRttMilis.set(snapshot.get(REQUEST_RTT_MILLIS));
+ stats.requestReTx.set(snapshot.get(REQUEST_RE_TX));
+ stats.numberOfSessionsExpired.set(snapshot.get(NUM_SESSIONS_EXPIRED));
+ stats.eapolLogoffRx.set(snapshot.get(EAPOL_LOGOFF_RX));
+ stats.eapolAuthSuccessTrans.set(snapshot.get(EAPOL_AUTH_SUCCESS_TRANS));
+ stats.eapolAuthFailureTrans.set(snapshot.get(EAPOL_AUTH_FAILURE_TRANS));
+ stats.eapolStartReqTrans.set(snapshot.get(EAPOL_START_REQ_TRANS));
+ stats.eapolMd5RspChall.set(snapshot.get(EAPOL_MD5_RESP_CHALLENGE));
+ stats.eapolTlsRespChall.set(snapshot.get(EAPOL_TLS_RESP_CHALLENGE));
+ stats.eapolTransRespNotNak.set(snapshot.get(EAPOL_TRANS_RESP_NOT_NAK));
+ stats.eapPktTxauthChooseEap.set(snapshot.get(EAP_PKT_TX_AUTH_CHOOSE_EAP));
+ stats.eapolAttrIdentity.set(snapshot.get(RES_ID_EAP_FRAMES_RX));
+ stats.eapolResIdentityMsgTrans.set(snapshot.get(EAPOL_RES_IDENTITY_MSG_TRANS));
+ stats.eapolFramesTx.set(snapshot.get(EAPOL_FRAMES_TX));
+ stats.authStateIdle.set(snapshot.get(AUTH_STATE_IDLE));
+ stats.requestIdFramesTx.set(snapshot.get(REQUEST_ID_FRAMES_TX));
+ stats.reqEapFramesTx.set(snapshot.get(REQUEST_EAP_FRAMES_TX));
+ stats.invalidPktType.set(snapshot.get(INVALID_PKT_TYPE));
+ stats.invalidBodyLength.set(snapshot.get(INVALID_BODY_LENGTH));
+ stats.validEapolFramesRx.set(snapshot.get(VALID_EAPOL_FRAMES_RX));
+ stats.pendingResSupp.set(snapshot.get(PENDING_RES_SUPPLICANT));
+
+ return stats;
+ }
+
+ public String toString() {
+ MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this.getClass());
+ helper.add(ACCEPT_RESPONSES_RX, acceptResponsesRx.get())
+ .add(REJECT_RESPONSES_RX, rejectResponsesRx.get())
+ .add(CHALLENGE_RESPONSES_RX, challengeResponsesRx.get())
+ .add(ACCESS_REQUESTS_TX, accessRequestsTx.get())
+ .add(PENDING_REQUESTS, pendingRequests.get())
+ .add(TIMED_OUT_PACKETS, timedOutPackets.get())
+ .add(UNKNOWN_TYPE_RX, unknownTypeRx.get())
+ .add(INVALID_VALIDATORS_RX, invalidValidatorsRx.get())
+ .add(DROPPED_RESPONSES_RX, droppedResponsesRx.get())
+ .add(MALFORMED_RESPONSES_RX, malformedResponsesRx.get())
+ .add(UNKNOWN_SERVER_RX, unknownServerRx.get())
+ .add(REQUEST_RTT_MILLIS, requestRttMilis.get())
+ .add(REQUEST_RE_TX, requestReTx.get())
+ .add(NUM_SESSIONS_EXPIRED, numberOfSessionsExpired.get())
+ .add(EAPOL_LOGOFF_RX, eapolLogoffRx.get())
+ .add(EAPOL_AUTH_SUCCESS_TRANS, eapolAuthSuccessTrans.get())
+ .add(EAPOL_AUTH_FAILURE_TRANS, eapolAuthFailureTrans.get())
+ .add(EAPOL_START_REQ_TRANS, eapolStartReqTrans.get())
+ .add(EAPOL_MD5_RESP_CHALLENGE, eapolMd5RspChall.get())
+ .add(EAPOL_TLS_RESP_CHALLENGE, eapolTlsRespChall.get())
+ .add(EAPOL_TRANS_RESP_NOT_NAK, eapolTransRespNotNak.get())
+ .add(EAP_PKT_TX_AUTH_CHOOSE_EAP, eapPktTxauthChooseEap.get())
+ .add(RES_ID_EAP_FRAMES_RX, eapolAttrIdentity.get())
+ .add(EAPOL_RES_IDENTITY_MSG_TRANS, eapolResIdentityMsgTrans.get())
+ .add(EAPOL_FRAMES_TX, eapolFramesTx.get())
+ .add(AUTH_STATE_IDLE, authStateIdle.get())
+ .add(REQUEST_ID_FRAMES_TX, requestIdFramesTx.get())
+ .add(REQUEST_EAP_FRAMES_TX, reqEapFramesTx.get())
+ .add(INVALID_PKT_TYPE, invalidPktType.get())
+ .add(INVALID_BODY_LENGTH, invalidBodyLength.get())
+ .add(VALID_EAPOL_FRAMES_RX, validEapolFramesRx.get())
+ .add(PENDING_RES_SUPPLICANT, pendingResSupp.get());
+ return helper.toString();
+ }
+
}
diff --git a/api/src/main/java/org/opencord/aaa/AaaStatisticsSnapshot.java b/api/src/main/java/org/opencord/aaa/AaaStatisticsSnapshot.java
new file mode 100644
index 0000000..7d3cfdc
--- /dev/null
+++ b/api/src/main/java/org/opencord/aaa/AaaStatisticsSnapshot.java
@@ -0,0 +1,81 @@
+/*
+ * 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 com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Immutable snapshot of AAA statistics.
+ */
+public class AaaStatisticsSnapshot {
+
+ private final ImmutableMap<String, Long> counters;
+
+ /**
+ * Gets the value of a counter.
+ *
+ * @param counterName name of the counter
+ * @return counter value, or 0 if it doesn't exist
+ */
+ public long get(String counterName) {
+ return counters.getOrDefault(counterName, 0L);
+ }
+
+ /**
+ * Creates a new empty snapshot with all counters initialized to 0.
+ */
+ public AaaStatisticsSnapshot() {
+ ImmutableMap.Builder<String, Long> builder = ImmutableMap.builder();
+
+ for (String name : AaaStatistics.COUNTER_NAMES) {
+ builder.put(name, 0L);
+ }
+
+ counters = builder.build();
+ }
+
+ /**
+ * Creates a new snapshot with the given counter values.
+ *
+ * @param counters counter values
+ */
+ public AaaStatisticsSnapshot(ImmutableMap<String, Long> counters) {
+ this.counters = counters;
+ }
+
+ /**
+ * Adds the given snapshot to this snapshot and returns a new snapshot with the aggregate values.
+ *
+ * @param other other snapshot to add to this one
+ * @return new aggregate snapshot
+ */
+ public AaaStatisticsSnapshot add(AaaStatisticsSnapshot other) {
+ ImmutableMap.Builder<String, Long> builder = ImmutableMap.builder();
+
+ counters.forEach((name, value) -> builder.put(name, value + other.counters.get(name)));
+
+ return new AaaStatisticsSnapshot(builder.build());
+ }
+
+ public String toString() {
+ MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this.getClass());
+ counters.forEach(helper::add);
+ return helper.toString();
+ }
+
+}
diff --git a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java
index 11c00e3..5dbbdad 100644
--- a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java
+++ b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsEvent.java
@@ -15,22 +15,26 @@
*/
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.
- */
+
+ /**
+ * Type of AuthenticationStatisticsEvent.
+ */
public enum Type {
+
/**
- * signifies that the Authentication Metrix Event stats has been updated.
+ * Signifies that the authentication statistics have been updated.
*/
STATS_UPDATE
}
+
public AuthenticationStatisticsEvent(Type type, AaaStatistics stats) {
super(type, stats);
}
diff --git a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java
index 37a2205..9f09387 100644
--- a/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java
+++ b/api/src/main/java/org/opencord/aaa/AuthenticationStatisticsService.java
@@ -19,46 +19,46 @@
import org.onosproject.event.ListenerService;
/**
- * Service for interacting with accounting module.
+ * Service for interacting with accounting statistics.
*/
-
public interface AuthenticationStatisticsService extends
-ListenerService<AuthenticationStatisticsEvent, AuthenticationStatisticsEventListener> {
+ ListenerService<AuthenticationStatisticsEvent, AuthenticationStatisticsEventListener> {
/**
- * Returns AaaStatistics object.
+ * Returns AaaStatistics object containing only local (this instance) statistics.
*
* @return AaaStatistics
*/
- public AaaStatistics getAaaStats();
+ AaaStatistics getAaaStats();
+
/**
- * Returns AuthenticationStatisticsDelegate object.
+ * Gets the cluster-wide statistics.
*
- * @return AuthenticationStatisticsDelegate
+ * @return snapshot containing cluster statistics
*/
- public AuthenticationStatisticsDelegate getStatsDelegate();
+ AaaStatisticsSnapshot getClusterStatistics();
/**
* Handle the roundTrip time of Radius Packet.
*
* @param identifier identifier of incoming radius packet
*/
- public void handleRoundtripTime(byte identifier);
+ void handleRoundtripTime(byte identifier);
/**
* Calculate average roundTrip time of multiple Packets.
*/
- public void calculatePacketRoundtripTime();
+ void calculatePacketRoundtripTime();
/**
* Put the identifier value to map.
*
* @param identifier identifier of incoming radius packet
*/
- public void putOutgoingIdentifierToMap(byte identifier);
+ void putOutgoingIdentifierToMap(byte identifier);
- /**
- * Reset all the values of aaa counters to 0.
- */
- public void resetAllCounters();
+ /**
+ * Reset all the values of aaa counters to 0.
+ */
+ void resetAllCounters();
}
diff --git a/app/pom.xml b/app/pom.xml
index 91c79e4..79fbd13 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -72,6 +72,13 @@
<dependency>
<groupId>org.onosproject</groupId>
+ <artifactId>onos-core-serializers</artifactId>
+ <version>${onos.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
<artifactId>onos-api</artifactId>
<version>${onos.version}</version>
<classifier>tests</classifier>
diff --git a/app/src/main/java/org/opencord/aaa/cli/AaaShowCountersCommand.java b/app/src/main/java/org/opencord/aaa/cli/AaaShowCountersCommand.java
index 054f6f1..3c08464 100644
--- a/app/src/main/java/org/opencord/aaa/cli/AaaShowCountersCommand.java
+++ b/app/src/main/java/org/opencord/aaa/cli/AaaShowCountersCommand.java
@@ -19,52 +19,27 @@
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.opencord.aaa.AaaStatistics;
+import org.opencord.aaa.AaaStatisticsSnapshot;
import org.opencord.aaa.AuthenticationStatisticsService;
/**
* Display current value of all aaa statistics counters.
*/
@Service
-@Command(scope = "onos", name = "show-aaa-counters",
+@Command(scope = "onos", name = "aaa-statistics",
description = "Display current value of all aaa statistics counters")
public class AaaShowCountersCommand extends AbstractShellCommand {
+
@Override
protected void doExecute() {
-
- AaaStatistics aaaStats = new AaaStatistics();
-
AuthenticationStatisticsService aaaStatisticsManager =
AbstractShellCommand.get(AuthenticationStatisticsService.class);
- aaaStats = aaaStatisticsManager.getAaaStats();
- System.out.format("%30s %10d\n", "AccessRequestsTx", aaaStats.getAccessRequestsTx());
- System.out.format("%30s %10d\n", "ChallengeResponsesRx", aaaStats.getChallengeResponsesRx());
- System.out.format("%30s %10d\n", "RequestReTx", aaaStats.getRequestReTx());
- System.out.format("%30s %10d\n", "AcceptResponsesRx", aaaStats.getAcceptResponsesRx());
- System.out.format("%30s %10d\n", "RejectResponsesRx", aaaStats.getRejectResponsesRx());
- System.out.format("%30s %10d\n", "PendingRequests", aaaStats.getPendingRequests());
- System.out.format("%30s %10d\n", "DroppedResponsesRx", aaaStats.getDroppedResponsesRx());
- System.out.format("%30s %10d\n", "InvalidValidatorsRx", aaaStats.getInvalidValidatorsRx());
- System.out.format("%30s %10d\n", "MalformedResponsesRx", aaaStats.getMalformedResponsesRx());
- System.out.format("%30s %10d\n", "UnknownServerRx", aaaStats.getUnknownServerRx());
- System.out.format("%30s %10d\n", "UnknownTypeRx", aaaStats.getUnknownTypeRx());
- System.out.format("%30s %10d\n", "RequestRttMillis", aaaStats.getRequestRttMilis());
- System.out.format("%30s %10d\n", "EapolLogoffRx", aaaStats.getEapolLogoffRx());
- System.out.format("%30s %10d\n", "EapolAuthSuccessTrans", aaaStats.getEapolAuthSuccessTrans());
- System.out.format("%30s %10d\n", "EapolAuthFailureTrans", aaaStats.getEapolAuthFailureTrans());
- System.out.format("%30s %10d\n", "EapolStartReqTrans", aaaStats.getEapolStartReqTrans());
- System.out.format("%30s %10d\n", "EapolTransRespNotNak", aaaStats.getEapolTransRespNotNak());
- System.out.format("%30s %10d\n", "EapPktTxauthChooseEap", aaaStats.getEapPktTxauthChooseEap());
- System.out.format("%30s %10d\n", "EapolResIdentityMsgTrans", aaaStats.getEapolResIdentityMsgTrans());
- System.out.format("%30s %10d\n", "AuthStateIdle", aaaStats.getAuthStateIdle());
- System.out.format("%30s %10d\n", "RequestIdFramesTx", aaaStats.getRequestIdFramesTx());
- System.out.format("%30s %10d\n", "ReqEapFramesTx", aaaStats.getReqEapFramesTx());
- System.out.format("%30s %10d\n", "InvalidPktType", aaaStats.getInvalidPktType());
- System.out.format("%30s %10d\n", "InvalidBodyLength", aaaStats.getInvalidBodyLength());
- System.out.format("%30s %10d\n", "ValidEapolFramesRx", aaaStats.getValidEapolFramesRx());
- System.out.format("%30s %10d\n", "PendingResSupp", aaaStats.getPendingResSupp());
- System.out.format("%30s %10d\n", "EapolFramesTx", aaaStats.getEapolFramesTx());
- System.out.format("%30s %10d\n", "TimedOutPackets", aaaStats.getTimedOutPackets());
+ AaaStatisticsSnapshot stats = aaaStatisticsManager.getClusterStatistics();
- }
+ for (String name : AaaStatistics.COUNTER_NAMES) {
+ print("%30s %10d", name, stats.get(name));
+ }
+
+ }
}
diff --git a/app/src/main/java/org/opencord/aaa/cli/AaaShowUsersCommand.java b/app/src/main/java/org/opencord/aaa/cli/AaaShowUsersCommand.java
index 11958a6..c562261 100644
--- a/app/src/main/java/org/opencord/aaa/cli/AaaShowUsersCommand.java
+++ b/app/src/main/java/org/opencord/aaa/cli/AaaShowUsersCommand.java
@@ -21,11 +21,17 @@
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.utils.Comparators;
import org.opencord.aaa.AuthenticationRecord;
import org.opencord.aaa.AuthenticationService;
import org.opencord.sadis.SadisService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
+import java.util.Comparator;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
/**
* Shows the users in the aaa.
*/
@@ -36,11 +42,19 @@
@Override
protected void doExecute() {
+ final Comparator<AuthenticationRecord> authenticationRecordComparator =
+ (a1, a2) -> Comparators.CONNECT_POINT_COMPARATOR.
+ compare(a1.supplicantConnectPoint(), a2.supplicantConnectPoint());
+
DeviceService devService = get(DeviceService.class);
SadisService sadisService = get(SadisService.class);
AuthenticationService authService = get(AuthenticationService.class);
- for (AuthenticationRecord auth : authService.getAuthenticationRecords()) {
+ List<AuthenticationRecord> authentications = newArrayList(authService.getAuthenticationRecords());
+
+ authentications.sort(authenticationRecordComparator);
+
+ for (AuthenticationRecord auth : authentications) {
String username = "UNKNOWN";
if (auth.username() != null) {
username = new String(auth.username());
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 79fc22c..85b1ce2 100644
--- a/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
+++ b/app/src/main/java/org/opencord/aaa/impl/AaaManager.java
@@ -49,7 +49,6 @@
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.ElementId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
@@ -66,6 +65,7 @@
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
+import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.MapEvent;
import org.onosproject.store.service.MapEventListener;
@@ -80,7 +80,6 @@
import org.opencord.aaa.AuthenticationEventListener;
import org.opencord.aaa.AuthenticationRecord;
import org.opencord.aaa.AuthenticationService;
-import org.opencord.aaa.AuthenticationStatisticsEvent;
import org.opencord.aaa.AuthenticationStatisticsService;
import org.opencord.aaa.RadiusCommunicator;
import org.opencord.aaa.RadiusOperationalStatusEvent;
@@ -101,7 +100,6 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import java.net.URI;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
@@ -113,8 +111,6 @@
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;
@@ -122,7 +118,6 @@
* AAA application for ONOS.
*/
@Component(immediate = true, property = {
- 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,
@@ -168,12 +163,10 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected RadiusOperationalStatusService radiusOperationalStatusService;
- protected AuthenticationStatisticsEventPublisher authenticationStatisticsPublisher;
protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
private final DeviceListener deviceListener = new InternalDeviceListener();
// 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;
@@ -228,12 +221,11 @@
// latest configuration
AaaConfig newCfg;
- ScheduledFuture<?> scheduledFuture;
ScheduledFuture<?> scheduledStatusServerChecker;
ScheduledExecutorService executor;
String configuredAaaServerAddress;
- HashSet<Byte> outPacketSet = new HashSet<Byte>();
- HashSet<Byte> outPacketSupp = new HashSet<Byte>();
+ HashSet<Byte> outPacketSet = new HashSet<>();
+ HashSet<Byte> outPacketSupp = new HashSet<>();
static final List<Byte> VALID_EAPOL_TYPE = Arrays.asList(EAPOL.EAPOL_START, EAPOL.EAPOL_LOGOFF, EAPOL.EAPOL_PACKET);
static final int HEADER_LENGTH = 4;
// Configuration properties factory
@@ -295,16 +287,7 @@
appId = coreService.registerApplication(APP_NAME);
KryoNamespace authSerializer = KryoNamespace.newBuilder()
- .register(byte[].class)
- .register(String.class)
- .register(long.class)
- .register(boolean.class)
- .register(URI.class)
- .register(DeviceId.class)
- .register(ElementId.class)
- .register(PortNumber.class)
- .register(ConnectPoint.class)
- .register(MacAddress.class)
+ .register(KryoNamespaces.API)
.register(AuthenticationRecord.class)
.build();
@@ -335,12 +318,8 @@
deviceService.addListener(deviceListener);
getConfiguredAaaServerAddress();
radiusOperationalStatusService.initialize(nasIpAddress.getAddress(), radiusSecret, impl);
- authenticationStatisticsPublisher =
- new AuthenticationStatisticsEventPublisher();
executor = Executors.newScheduledThreadPool(3);
- scheduledFuture = executor.scheduleAtFixedRate(authenticationStatisticsPublisher,
- 0, statisticsGenerationPeriodInSeconds, TimeUnit.SECONDS);
scheduledStatusServerChecker = executor.scheduleAtFixedRate(new ServerStatusChecker(), 0,
operationalStatusEventGenerationPeriodInSeconds, TimeUnit.SECONDS);
@@ -357,7 +336,6 @@
impl.deactivate();
deviceService.removeListener(deviceListener);
eventDispatcher.removeSink(AuthenticationEvent.class);
- scheduledFuture.cancel(true);
scheduledStatusServerChecker.cancel(true);
executor.shutdown();
@@ -369,11 +347,7 @@
public void modified(ComponentContext context) {
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");
+ String s = Tools.get(properties, "operationalStatusEventGenerationPeriodInSeconds");
operationalStatusEventGenerationPeriodInSeconds = Strings.isNullOrEmpty(s)
? OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT
: Integer.parseInt(s.trim());
@@ -1121,51 +1095,6 @@
}
}
- 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());
- log.debug("TimedOutPackets----" + aaaStatisticsManager.getAaaStats().getTimedOutPackets());
- log.debug("EapolLogoffRx---" + aaaStatisticsManager.getAaaStats().getEapolLogoffRx());
- log.debug("EapolAuthSuccessTrans---" + aaaStatisticsManager.getAaaStats().getEapolAuthSuccessTrans());
- log.debug("EapolAuthFailureTrans---" +
- aaaStatisticsManager.getAaaStats().getEapolAuthFailureTrans());
- log.debug("EapolStartReqTrans---" +
- aaaStatisticsManager.getAaaStats().getEapolStartReqTrans());
- log.debug("EapolTransRespNotNak---" +
- aaaStatisticsManager.getAaaStats().getEapolTransRespNotNak());
- log.debug("EapPktTxauthChooseEap---" +
- aaaStatisticsManager.getAaaStats().getEapPktTxauthChooseEap());
- log.debug("EapolResIdentityMsgTrans---" +
- aaaStatisticsManager.getAaaStats().getEapolResIdentityMsgTrans());
- log.debug("EapolFramesTx---" + aaaStatisticsManager.getAaaStats().getEapolFramesTx());
- log.debug("AuthStateIdle---" + aaaStatisticsManager.getAaaStats().getAuthStateIdle());
- log.debug("RequestIdFramesTx---" + aaaStatisticsManager.getAaaStats().getRequestIdFramesTx());
- log.debug("ReqEapFramesTx---" + aaaStatisticsManager.getAaaStats().getReqEapFramesTx());
- log.debug("InvalidPktType---" + aaaStatisticsManager.getAaaStats().getInvalidPktType());
- log.debug("InvalidBodyLength---" + aaaStatisticsManager.getAaaStats().getInvalidBodyLength());
- log.debug("ValidEapolFramesRx---" + aaaStatisticsManager.getAaaStats().getValidEapolFramesRx());
- log.debug("PendingResSupp---" + aaaStatisticsManager.getAaaStats().getPendingResSupp());
- log.debug("ResIdEapFramesRx---" + aaaStatisticsManager.getAaaStats().getEapolattrIdentity());
- aaaStatisticsManager.getStatsDelegate().
- notify(new AuthenticationStatisticsEvent(AuthenticationStatisticsEvent.Type.STATS_UPDATE,
- aaaStatisticsManager.getAaaStats()));
- }
- }
-
private class ServerStatusChecker implements Runnable {
@Override
public void run() {
diff --git a/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java b/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java
index 125898e..8bb2f53 100644
--- a/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java
+++ b/app/src/main/java/org/opencord/aaa/impl/AaaStatisticsManager.java
@@ -16,60 +16,171 @@
package org.opencord.aaa.impl;
+import com.google.common.base.Strings;
+import org.onlab.util.KryoNamespace;
+import org.onlab.util.SafeRecurringTask;
+import org.onlab.util.Tools;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
+import org.onosproject.store.cluster.messaging.ClusterMessage;
+import org.onosproject.store.cluster.messaging.MessageSubject;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
import org.opencord.aaa.AaaStatistics;
-import org.opencord.aaa.AuthenticationStatisticsDelegate;
+import org.opencord.aaa.AaaStatisticsSnapshot;
import org.opencord.aaa.AuthenticationStatisticsEvent;
import org.opencord.aaa.AuthenticationStatisticsEventListener;
import org.opencord.aaa.AuthenticationStatisticsService;
+import org.osgi.service.component.ComponentContext;
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 java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
+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.STATISTICS_SYNC_PERIOD;
+import static org.opencord.aaa.impl.OsgiPropertyConstants.STATISTICS_SYNC_PERIOD_DEFAULT;
import static org.slf4j.LoggerFactory.getLogger;
-
-
-@Component(immediate = true)
+/**
+ * Manages collection and publishing of statistics for the AAA application.
+ */
+@Component(immediate = true, property = {
+ STATISTICS_GENERATION_PERIOD + ":Integer=" + STATISTICS_GENERATION_PERIOD_DEFAULT,
+ STATISTICS_SYNC_PERIOD + ":Integer=" + STATISTICS_SYNC_PERIOD_DEFAULT,
+})
public class AaaStatisticsManager
-extends AbstractListenerManager<AuthenticationStatisticsEvent, AuthenticationStatisticsEventListener>
-implements AuthenticationStatisticsService {
+ extends AbstractListenerManager<AuthenticationStatisticsEvent, AuthenticationStatisticsEventListener>
+ implements AuthenticationStatisticsService {
- private AuthenticationStatisticsDelegate statsDelegate;
+ private static final String AAA_STATISTICS_LEADERSHIP = "aaa-statistics";
- @Override
- public AuthenticationStatisticsDelegate getStatsDelegate() {
- return statsDelegate;
- }
+ private static final MessageSubject RESET_SUBJECT = new MessageSubject("aaa-statistics-reset");
+
+ private int statisticsGenerationPeriodInSeconds = STATISTICS_GENERATION_PERIOD_DEFAULT;
+ private int statisticsSyncPeriodInSeconds = STATISTICS_SYNC_PERIOD_DEFAULT;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ClusterCommunicationService clusterCommunicationService;
+
+ private ScheduledExecutorService executor;
+
+ private ScheduledFuture<?> publisherTask;
+ private ScheduledFuture<?> syncTask;
+
+ private EventuallyConsistentMap<NodeId, AaaStatisticsSnapshot> statistics;
private final Logger log = getLogger(getClass());
private AaaStatistics aaaStats;
- public Map<Byte, Long> outgoingPacketMap = new HashMap<Byte, Long>();
+ private Map<Byte, Long> outgoingPacketMap = new HashMap<>();
private static final int PACKET_COUNT_FOR_AVERAGE_RTT_CALCULATION = 5;
+ KryoNamespace serializer = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(AaaStatisticsSnapshot.class)
+ .register(ClusterMessage.class)
+ .register(MessageSubject.class)
+ .build();
+
@Override
public AaaStatistics getAaaStats() {
return aaaStats;
}
+ @Override
+ public AaaStatisticsSnapshot getClusterStatistics() {
+ return aggregate();
+ }
+
@Activate
- public void activate() {
+ public void activate(ComponentContext context) {
log.info("Activate aaaStatisticsManager");
- aaaStats = new AaaStatistics();
- statsDelegate = new InternalAuthenticationDelegateForStatistics();
+ modified(context);
+
+ statistics = storageService.<NodeId, AaaStatisticsSnapshot>eventuallyConsistentMapBuilder()
+ .withName("aaa-statistics")
+ .withSerializer(serializer)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
+ AaaStatisticsSnapshot snapshot = statistics.get(clusterService.getLocalNode().id());
+ if (snapshot == null) {
+ aaaStats = new AaaStatistics();
+ } else {
+ aaaStats = AaaStatistics.fromSnapshot(snapshot);
+ }
+
+ leadershipService.runForLeadership(AAA_STATISTICS_LEADERSHIP);
+
eventDispatcher.addSink(AuthenticationStatisticsEvent.class, listenerRegistry);
+
+ executor = Executors.newScheduledThreadPool(1);
+
+ clusterCommunicationService.addSubscriber(RESET_SUBJECT, Serializer.using(serializer)::decode,
+ this::resetLocal, executor);
+
+ syncTask = executor.scheduleAtFixedRate(SafeRecurringTask.wrap(this::syncStats),
+ 0, statisticsSyncPeriodInSeconds, TimeUnit.SECONDS);
+
+ publisherTask = executor.scheduleAtFixedRate(SafeRecurringTask.wrap(this::publishStats),
+ 0, statisticsGenerationPeriodInSeconds, TimeUnit.SECONDS);
}
@Deactivate
public void deactivate() {
+ clusterCommunicationService.removeSubscriber(RESET_SUBJECT);
+
+ publisherTask.cancel(true);
+ syncTask.cancel(true);
+ executor.shutdownNow();
+
+ leadershipService.withdraw(AAA_STATISTICS_LEADERSHIP);
+
eventDispatcher.removeSink(AuthenticationStatisticsEvent.class);
}
+ @Modified
+ public void modified(ComponentContext context) {
+ 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, "statisticsSyncPeriodInSeconds");
+ statisticsSyncPeriodInSeconds = Strings.isNullOrEmpty(s) ? STATISTICS_SYNC_PERIOD_DEFAULT
+ : Integer.parseInt(s.trim());
+ }
+
@Override
public void handleRoundtripTime(byte inPacketIdentifier) {
long inTimeInMilis = System.currentTimeMillis();
@@ -83,7 +194,8 @@
@Override
public void resetAllCounters() {
- aaaStats.resetAllCounters();
+ ClusterMessage reset = new ClusterMessage(clusterService.getLocalNode().id(), RESET_SUBJECT, new byte[]{});
+ clusterCommunicationService.broadcastIncludeSelf(reset, RESET_SUBJECT, Serializer.using(serializer)::encode);
}
@Override
@@ -100,14 +212,46 @@
}
/**
- *Delegate allowing the StateMachine to notify us of events.
+ * Pushes in-memory stats into the eventually-consistent map for cluster-wide retention.
*/
- private class InternalAuthenticationDelegateForStatistics implements AuthenticationStatisticsDelegate {
- @Override
- public void notify(AuthenticationStatisticsEvent authenticationStatisticsEvent) {
- log.debug("Authentication Statistics event {} for {}", authenticationStatisticsEvent.type(),
- authenticationStatisticsEvent.subject());
- post(authenticationStatisticsEvent);
+ private void syncStats() {
+ calculatePacketRoundtripTime();
+
+ statistics.put(clusterService.getLocalNode().id(), aaaStats.snapshot());
+ }
+
+ /**
+ * Aggregates cluster-wise stats from the ec-map.
+ *
+ * @return aggregate stats
+ */
+ private AaaStatisticsSnapshot aggregate() {
+ return statistics.values().stream()
+ .reduce(new AaaStatisticsSnapshot(), AaaStatisticsSnapshot::add);
+ }
+
+ /**
+ * Publishes cluster-wide stats.
+ */
+ private void publishStats() {
+ // only publish if we are the leader
+ if (!Objects.equals(leadershipService.getLeader(AAA_STATISTICS_LEADERSHIP),
+ clusterService.getLocalNode().id())) {
+ return;
}
+
+ AaaStatisticsSnapshot clusterStats = aggregate();
+
+ if (log.isDebugEnabled()) {
+ log.debug("Notifying stats: {}", clusterStats);
+ }
+
+ post(new AuthenticationStatisticsEvent(AuthenticationStatisticsEvent.Type.STATS_UPDATE,
+ AaaStatistics.fromSnapshot(clusterStats)));
+ }
+
+ private void resetLocal(ClusterMessage m) {
+ aaaStats.resetAllCounters();
+ syncStats();
}
}
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 1c59799..34a2cc3 100644
--- a/app/src/main/java/org/opencord/aaa/impl/OsgiPropertyConstants.java
+++ b/app/src/main/java/org/opencord/aaa/impl/OsgiPropertyConstants.java
@@ -27,6 +27,9 @@
public static final String STATISTICS_GENERATION_PERIOD = "statisticsGenerationPeriodInSeconds";
public static final int STATISTICS_GENERATION_PERIOD_DEFAULT = 20;
+ public static final String STATISTICS_SYNC_PERIOD = "statisticsSyncPeriodInSeconds";
+ public static final int STATISTICS_SYNC_PERIOD_DEFAULT = 5;
+
public static final String OPERATIONAL_STATUS_SERVER_EVENT_GENERATION =
"operationalStatusEventGenerationPeriodInSeconds";
public static final int OPERATIONAL_STATUS_SERVER_EVENT_GENERATION_DEFAULT = 30;
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 4309e31..839d0b1 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaManagerTest.java
@@ -26,6 +26,9 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
+import org.onosproject.cluster.ClusterServiceAdapter;
+import org.onosproject.cluster.LeadershipServiceAdapter;
+import org.onosproject.cluster.NodeId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.event.DefaultEventSinkRegistry;
import org.onosproject.event.Event;
@@ -34,6 +37,7 @@
import org.onosproject.net.config.Config;
import org.onosproject.net.config.NetworkConfigRegistryAdapter;
import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationServiceAdapter;
import org.onosproject.store.service.TestStorageService;
import org.opencord.aaa.AaaConfig;
@@ -77,6 +81,13 @@
}
}
+ static final class TestLeadershipService extends LeadershipServiceAdapter {
+ @Override
+ public NodeId getLeader(String path) {
+ return new ClusterServiceAdapter().getLocalNode().id();
+ }
+ }
+
/**
* Mocks the network config registry.
*/
@@ -124,9 +135,13 @@
aaaManager.cfgService = new MockCfgService();
aaaManager.storageService = new TestStorageService();
aaaStatisticsManager = new AaaStatisticsManager();
+ aaaStatisticsManager.storageService = new TestStorageService();
+ aaaStatisticsManager.clusterService = new ClusterServiceAdapter();
+ aaaStatisticsManager.leadershipService = new TestLeadershipService();
+ aaaStatisticsManager.clusterCommunicationService = new ClusterCommunicationServiceAdapter();
aaaManager.radiusOperationalStatusService = new RadiusOperationalStatusManager();
TestUtils.setField(aaaStatisticsManager, "eventDispatcher", new TestEventDispatcher());
- aaaStatisticsManager.activate();
+ aaaStatisticsManager.activate(new MockComponentContext());
aaaManager.aaaStatisticsManager = this.aaaStatisticsManager;
TestUtils.setField(aaaManager, "eventDispatcher", new TestEventDispatcher());
aaaManager.activate(new AaaTestBase.MockComponentContext());
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 573e4de..c9564b0 100644
--- a/app/src/test/java/org/opencord/aaa/impl/AaaStatisticsTest.java
+++ b/app/src/test/java/org/opencord/aaa/impl/AaaStatisticsTest.java
@@ -26,6 +26,7 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
+import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.event.DefaultEventSinkRegistry;
@@ -38,6 +39,7 @@
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketService;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationServiceAdapter;
import org.onosproject.store.service.TestStorageService;
import org.opencord.aaa.AaaConfig;
import org.slf4j.Logger;
@@ -144,9 +146,13 @@
aaaManager.cfgService = new MockCfgService();
aaaManager.storageService = new TestStorageService();
aaaStatisticsManager = new AaaStatisticsManager();
+ aaaStatisticsManager.storageService = new TestStorageService();
+ aaaStatisticsManager.clusterService = new ClusterServiceAdapter();
+ aaaStatisticsManager.leadershipService = new AaaManagerTest.TestLeadershipService();
+ aaaStatisticsManager.clusterCommunicationService = new ClusterCommunicationServiceAdapter();
aaaSupplicantStatsManager = new AaaSupplicantMachineStatsManager();
TestUtils.setField(aaaStatisticsManager, "eventDispatcher", new TestEventDispatcher());
- aaaStatisticsManager.activate();
+ aaaStatisticsManager.activate(new MockComponentContext());
TestUtils.setField(aaaSupplicantStatsManager, "eventDispatcher", new TestEventDispatcher());
aaaSupplicantStatsManager.activate();
aaaManager.aaaStatisticsManager = this.aaaStatisticsManager;