AAA App refactoring
- optimized lookup of state machines
- modified getter/setter method names to match ONOS project standards
- made StateMachine local members private and add accesor methods
- added unit tests for StateMachine lookups
Change-Id: I5704ddc4d8b1b3c887be1262f2edd78965e4a8bf
diff --git a/src/main/java/org/onosproject/aaa/AAA.java b/src/main/java/org/onosproject/aaa/AAA.java
index 7e3de88..e265668 100644
--- a/src/main/java/org/onosproject/aaa/AAA.java
+++ b/src/main/java/org/onosproject/aaa/AAA.java
@@ -15,8 +15,13 @@
*/
package org.onosproject.aaa;
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Dictionary;
+import java.util.Optional;
+import java.util.Set;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -61,15 +66,7 @@
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
+import com.google.common.base.Strings;
import static org.onosproject.net.packet.PacketPriority.CONTROL;
import static org.slf4j.LoggerFactory.getLogger;
@@ -80,35 +77,6 @@
*/
@Component(immediate = true)
public class AAA {
- // a list of our dependencies :
- // to register with ONOS as an application - described next
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected CoreService coreService;
-
- // to receive Packet-in events that we'll respond to
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected PacketService packetService;
-
- // end host information
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected HostService hostService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected VoltTenantService voltTenantService;
-
- // for verbose output
- private final Logger log = getLogger(getClass());
-
- // our application-specific event handler
- private ReactivePacketProcessor processor = new ReactivePacketProcessor();
-
- // our unique identifier
- private ApplicationId appId;
-
- // Map of state machines. Each state machine is represented by an
- // unique identifier on the switch: dpid + port number
- Map stateMachineMap = null;
-
// RADIUS server IP address
private static final String DEFAULT_RADIUS_IP = "192.168.1.10";
// NAS IP address
@@ -125,43 +93,84 @@
private static final String DEFAULT_RADIUS_SWITCH = "of:90e2ba82f97791e9";
// Radius Port Number
private static final String DEFAULT_RADIUS_PORT = "129";
-
+ // for verbose output
+ private final Logger log = getLogger(getClass());
+ // a list of our dependencies :
+ // to register with ONOS as an application - described next
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+ // to receive Packet-in events that we'll respond to
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected PacketService packetService;
+ // end host information
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected VoltTenantService voltTenantService;
+ // Parsed RADIUS server IP address
+ protected InetAddress parsedRadiusIpAddress;
+ // Parsed NAS IP address
+ protected InetAddress parsedNasIpAddress;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService cfgService;
+ // our application-specific event handler
+ private ReactivePacketProcessor processor = new ReactivePacketProcessor();
+ // our unique identifier
+ private ApplicationId appId;
@Property(name = "radiusIpAddress", value = DEFAULT_RADIUS_IP,
label = "RADIUS IP Address")
private String radiusIpAddress = DEFAULT_RADIUS_IP;
-
@Property(name = "nasIpAddress", value = DEFAULT_NAS_IP,
label = "NAS IP Address")
private String nasIpAddress = DEFAULT_NAS_IP;
-
@Property(name = "radiusMacAddress", value = RADIUS_MAC_ADDRESS,
label = "RADIUS MAC Address")
private String radiusMacAddress = RADIUS_MAC_ADDRESS;
-
@Property(name = "nasMacAddress", value = NAS_MAC_ADDRESS,
label = "NAS MAC Address")
private String nasMacAddress = NAS_MAC_ADDRESS;
-
@Property(name = "radiusSecret", value = DEFAULT_RADIUS_SECRET,
label = "RADIUS shared secret")
private String radiusSecret = DEFAULT_RADIUS_SECRET;
-
@Property(name = "radiusSwitchId", value = DEFAULT_RADIUS_SWITCH,
label = "Radius switch")
private String radiusSwitch = DEFAULT_RADIUS_SWITCH;
-
@Property(name = "radiusPortNumber", value = DEFAULT_RADIUS_PORT,
label = "Radius port")
private String radiusPort = DEFAULT_RADIUS_PORT;
- // Parsed RADIUS server IP address
- protected InetAddress parsedRadiusIpAddress;
+ /**
+ * Builds an EAPOL packet based on the given parameters.
+ *
+ * @param dstMac destination MAC address
+ * @param srcMac source MAC address
+ * @param vlan vlan identifier
+ * @param eapolType EAPOL type
+ * @param eap EAP payload
+ * @return Ethernet frame
+ */
+ private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
+ short vlan, byte eapolType, EAP eap) {
- // Parsed NAS IP address
- protected InetAddress parsedNasIpAddress;
+ Ethernet eth = new Ethernet();
+ eth.setDestinationMACAddress(dstMac.toBytes());
+ eth.setSourceMACAddress(srcMac.toBytes());
+ eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
+ if (vlan != Ethernet.VLAN_UNTAGGED) {
+ eth.setVlanID(vlan);
+ }
+ //eapol header
+ EAPOL eapol = new EAPOL();
+ eapol.setEapolType(eapolType);
+ eapol.setPacketLength(eap.getLength());
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected ComponentConfigService cfgService;
+ //eap part
+ eapol.setPayload(eap);
+
+ eth.setPayload(eapol);
+ eth.setPad(true);
+ return eth;
+ }
@Modified
public void modified(ComponentContext context) {
@@ -207,11 +216,10 @@
// register our event handler
packetService.addProcessor(processor, PacketProcessor.director(2));
requestIntercepts();
- // Instantiate the map of the state machines
- stateMachineMap = Collections.synchronizedMap(Maps.newHashMap());
+
+ StateMachine.initializeMaps();
hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress));
-
}
@Deactivate
@@ -223,6 +231,7 @@
// de-register and null our handler
packetService.removeProcessor(processor);
processor = null;
+ StateMachine.destroyMaps();
}
/**
@@ -260,39 +269,6 @@
packetService.cancelPackets(radSelector, CONTROL, appId);
}
- /**
- * Builds an EAPOL packet based on the given parameters.
- *
- * @param dstMac destination MAC address
- * @param srcMac source MAC address
- * @param vlan vlan identifier
- * @param eapolType EAPOL type
- * @param eap EAP payload
- * @return Ethernet frame
- */
- private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
- short vlan, byte eapolType, EAP eap) {
-
- Ethernet eth = new Ethernet();
- eth.setDestinationMACAddress(dstMac.toBytes());
- eth.setSourceMACAddress(srcMac.toBytes());
- eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
- if (vlan != Ethernet.VLAN_UNTAGGED) {
- eth.setVlanID(vlan);
- }
- //eapol header
- EAPOL eapol = new EAPOL();
- eapol.setEapolType(eapolType);
- eapol.setPacketLength(eap.getLength());
-
- //eap part
- eapol.setPayload(eap);
-
- eth.setPayload(eapol);
- eth.setPad(true);
- return eth;
- }
-
// our handler defined as a private inner class
/**
@@ -351,7 +327,11 @@
DeviceId deviceId = inPacket.receivedFrom().deviceId();
PortNumber portNumber = inPacket.receivedFrom().port();
String sessionId = deviceId.toString() + portNumber.toString();
- StateMachine stateMachine = getStateMachine(sessionId);
+ StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
+ if (stateMachine == null) {
+ stateMachine = new StateMachine(sessionId, voltTenantService);
+ }
+
EAPOL eapol = (EAPOL) ethPkt.getPayload();
@@ -359,17 +339,17 @@
case EAPOL.EAPOL_START:
try {
stateMachine.start();
- stateMachine.supplicantConnectpoint = inPacket.receivedFrom();
+ stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
//send an EAP Request/Identify to the supplicant
- EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.getIdentifier(), EAP.ATTR_IDENTITY, null);
+ EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L),
ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
eapPayload);
- stateMachine.supplicantAddress = srcMAC;
- stateMachine.vlanId = ethPkt.getVlanID();
+ stateMachine.setSupplicantAddress(srcMAC);
+ stateMachine.setVlanId(ethPkt.getVlanID());
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
+ this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
} catch (StateMachineException e) {
e.printStackTrace();
}
@@ -386,7 +366,7 @@
//request id access to RADIUS
RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
eapPacket.getIdentifier());
- radiusPayload.setIdentifier(stateMachine.getIdentifier());
+ radiusPayload.setIdentifier(stateMachine.identifier());
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
eapPacket.getData());
stateMachine.setUsername(eapPacket.getData());
@@ -409,20 +389,20 @@
case EAP.ATTR_MD5:
//verify if the EAP identifier corresponds to the challenge identifier from the client state
//machine.
- if (eapPacket.getIdentifier() == stateMachine.getChallengeIdentifier()) {
+ if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
//send the RADIUS challenge response
RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
eapPacket.getIdentifier());
- radiusPayload.setIdentifier(stateMachine.getChallengeIdentifier());
+ radiusPayload.setIdentifier(stateMachine.challengeIdentifier());
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
- stateMachine.getUsername());
+ stateMachine.username());
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
AAA.this.parsedNasIpAddress.getAddress());
radiusPayload.encapsulateMessage(eapPacket);
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
- stateMachine.getChallengeState());
+ stateMachine.challengeState());
radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
sendRadiusMessage(radiusPayload);
}
@@ -432,16 +412,16 @@
//request id access to RADIUS
RADIUS radiusPayload = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
eapPacket.getIdentifier());
- radiusPayload.setIdentifier(stateMachine.getIdentifier());
+ radiusPayload.setIdentifier(stateMachine.identifier());
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
- stateMachine.getUsername());
+ stateMachine.username());
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
AAA.this.parsedNasIpAddress.getAddress());
radiusPayload.encapsulateMessage(eapPacket);
radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
- stateMachine.getChallengeState());
+ stateMachine.challengeState());
stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
@@ -468,7 +448,7 @@
* @param radiusPacket RADIUS packet coming from the RADIUS server.
*/
private void handleRadiusPacket(RADIUS radiusPacket) {
- StateMachine stateMachine = getStateMachineById(radiusPacket.getIdentifier());
+ StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
if (stateMachine == null) {
log.error("Invalid session identifier, exiting...");
return;
@@ -481,10 +461,10 @@
byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
eapPayload = radiusPacket.decapsulateMessage();
stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
- eth = buildEapolResponse(stateMachine.supplicantAddress,
- MacAddress.valueOf(1L), stateMachine.vlanId, EAPOL.EAPOL_PACKET,
+ eth = buildEapolResponse(stateMachine.supplicantAddress(),
+ MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
eapPayload);
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
+ this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
break;
case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
try {
@@ -493,10 +473,10 @@
radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
eapPayload = new EAP();
eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
- eth = buildEapolResponse(stateMachine.supplicantAddress,
- MacAddress.valueOf(1L), stateMachine.vlanId, EAPOL.EAPOL_PACKET,
+ eth = buildEapolResponse(stateMachine.supplicantAddress(),
+ MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
eapPayload);
- this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint);
+ this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
stateMachine.authorizeAccess();
} catch (StateMachineException e) {
@@ -515,51 +495,6 @@
}
}
- private StateMachine getStateMachineById(byte identifier) {
- StateMachine stateMachine = null;
- Set stateMachineSet = stateMachineMap.entrySet();
-
- synchronized (stateMachineMap) {
- Iterator itr = stateMachineSet.iterator();
- while (itr.hasNext()) {
- Map.Entry entry = (Map.Entry) itr.next();
- stateMachine = (StateMachine) entry.getValue();
- if (identifier == stateMachine.getIdentifier()) {
- //the state machine has already been created for this session session
- stateMachine = (StateMachine) entry.getValue();
- break;
- }
- }
- }
-
- return stateMachine;
- }
-
- private StateMachine getStateMachine(String sessionId) {
- StateMachine stateMachine = null;
- Set stateMachineSet = stateMachineMap.entrySet();
-
- synchronized (stateMachineMap) {
- Iterator itr = stateMachineSet.iterator();
- while (itr.hasNext()) {
-
- Map.Entry entry = (Map.Entry) itr.next();
- if (sessionId.equals(entry.getKey())) {
- //the state machine has already been created for this session session
- stateMachine = (StateMachine) entry.getValue();
- break;
- }
- }
- }
-
- if (stateMachine == null) {
- stateMachine = new StateMachine(sessionId, voltTenantService);
- stateMachineMap.put(sessionId, stateMachine);
- }
-
- return stateMachine;
- }
-
private void sendRadiusMessage(RADIUS radiusMessage) {
Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress));
Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst();