| /* |
| * Copyright 2017-present Open Networking Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.opencord.aaa.impl; |
| |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| import org.apache.felix.scr.annotations.Component; |
| import org.apache.felix.scr.annotations.Service; |
| import org.onlab.packet.RADIUS; |
| import org.onlab.packet.RADIUSAttribute; |
| import org.onosproject.event.AbstractListenerManager; |
| import org.opencord.aaa.RadiusOperationalStatusService; |
| import org.opencord.aaa.RadiusCommunicator; |
| import org.opencord.aaa.RadiusOperationalStatusEvent; |
| import org.opencord.aaa.RadiusOperationalStatusEventDelegate; |
| import org.opencord.aaa.RadiusOperationalStatusEventListener; |
| import org.apache.felix.scr.annotations.Activate; |
| import org.apache.felix.scr.annotations.Deactivate; |
| import org.slf4j.Logger; |
| |
| @Service |
| @Component(immediate = true) |
| public class RadiusOperationalStatusManager |
| extends AbstractListenerManager<RadiusOperationalStatusEvent, RadiusOperationalStatusEventListener> |
| implements RadiusOperationalStatusService { |
| |
| private byte[] address; |
| private String secret; |
| private RadiusCommunicator impl; |
| private RadiusOperationalStatusEventDelegate radiusOprStDelegate; |
| |
| private long operationalStatusServerTimeoutInMillis; |
| private boolean statusServerReqSent; |
| private final Logger log = getLogger(getClass()); |
| |
| private Boolean fakeAccessRequestPacketRecieved = false; |
| private long fakeAccessRequestOutTimeInMillis; |
| |
| private Boolean serverStatusPacketRecieved = false; |
| private long serverStatusOutTimeInMillis; |
| |
| private OperationalStatus radiusServerOperationalStatus; |
| public static final byte AAA_REQUEST_ID_STATUS_REQUEST = 0; |
| public static final byte AAA_REQUEST_ID_FAKE_ACCESS_REQUEST = 1; |
| |
| private RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode; |
| |
| private static final String DUMMY_USER = new String("dummy-user"); |
| private static final byte RADIUS_CODE_STATUS_REQUEST = (byte) 12; |
| private long lastRadiusPacketInTimeInMillis; |
| |
| public void setOperationalStatusServerTimeoutInMillis(long operationalStatusServerTimeoutInMillis) { |
| this.operationalStatusServerTimeoutInMillis = operationalStatusServerTimeoutInMillis; |
| } |
| |
| public void setRadiusOperationalStatusEvaluationMode( |
| RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode) { |
| this.radiusOperationalStatusEvaluationMode = radiusOperationalStatusEvaluationMode; |
| } |
| |
| public RadiusOperationalStatusEventDelegate getRadiusOprStDelegate() { |
| return radiusOprStDelegate; |
| } |
| |
| @Override |
| public void setOutTimeInMillis(byte identifier) { |
| if (identifier == AAA_REQUEST_ID_STATUS_REQUEST) { |
| serverStatusOutTimeInMillis = System.currentTimeMillis(); |
| } else { |
| fakeAccessRequestOutTimeInMillis = System.currentTimeMillis(); |
| } |
| } |
| |
| @Override |
| public String getRadiusServerOperationalStatus() { |
| return radiusServerOperationalStatus.toString(); |
| } |
| |
| @Activate |
| public void activate() { |
| radiusOprStDelegate = new InternalRadiusOperationalStatusDelegate(); |
| eventDispatcher.addSink(RadiusOperationalStatusEvent.class, listenerRegistry); |
| radiusServerOperationalStatus = OperationalStatus.UNKNOWN; |
| } |
| |
| public void setStatusServerReqSent(boolean statusServerReqSent) { |
| this.statusServerReqSent = statusServerReqSent; |
| } |
| |
| @Deactivate |
| public void deactivate() { |
| eventDispatcher.removeSink(RadiusOperationalStatusEvent.class); |
| } |
| |
| public void initialize(byte[] address, String secret, RadiusCommunicator impl) { |
| this.address = address; |
| this.secret = secret; |
| this.impl = impl; |
| } |
| |
| public boolean isRadiusResponseForOperationalStatus(byte identifier) { |
| if (identifier == AAA_REQUEST_ID_STATUS_REQUEST || identifier == AAA_REQUEST_ID_FAKE_ACCESS_REQUEST) { |
| return true; |
| } else { |
| lastRadiusPacketInTimeInMillis = System.currentTimeMillis(); |
| return false; |
| } |
| } |
| |
| public void handleRadiusPacketForOperationalStatus(RADIUS radiusPacket) { |
| byte radiusPktIdentifier = radiusPacket.getIdentifier(); |
| |
| if (radiusPktIdentifier == AAA_REQUEST_ID_STATUS_REQUEST) { |
| long serverStatusRttInMillis = System.currentTimeMillis() - serverStatusOutTimeInMillis; |
| if (serverStatusRttInMillis < operationalStatusServerTimeoutInMillis) { |
| serverStatusPacketRecieved = true; |
| } |
| } else { |
| long fakeAccessRttInMillis = System.currentTimeMillis() - fakeAccessRequestOutTimeInMillis; |
| if (fakeAccessRttInMillis < operationalStatusServerTimeoutInMillis) { |
| fakeAccessRequestPacketRecieved = true; |
| } |
| } |
| |
| switch (radiusPacket.getCode()) { |
| case RADIUS.RADIUS_CODE_ACCESS_ACCEPT: |
| synchronized (serverStatusPacketRecieved) { |
| serverStatusPacketRecieved.notify(); |
| } |
| break; |
| case RADIUS.RADIUS_CODE_ACCESS_REJECT: |
| synchronized (fakeAccessRequestPacketRecieved) { |
| fakeAccessRequestPacketRecieved.notify(); |
| } |
| break; |
| default: |
| log.warn("Unexpected Radius message for operational status recieved " |
| + "with code: {}", radiusPacket.getCode()); |
| } |
| } |
| |
| public void checkServerStatusUsingStatusServerRequest() throws InterruptedException { |
| RADIUS radiusStatusServerRequest; |
| // identifier = 0 for status server |
| radiusStatusServerRequest = new RADIUS(RADIUS_CODE_STATUS_REQUEST, AAA_REQUEST_ID_STATUS_REQUEST); |
| |
| radiusStatusServerRequest.setIdentifier(AAA_REQUEST_ID_STATUS_REQUEST); |
| radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes()); |
| |
| radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address); |
| radiusStatusServerRequest.addMessageAuthenticator(secret); |
| setOutTimeInMillis(radiusStatusServerRequest.getIdentifier()); |
| impl.sendRadiusPacket(radiusStatusServerRequest, null); |
| synchronized (serverStatusPacketRecieved) { |
| serverStatusPacketRecieved.wait(operationalStatusServerTimeoutInMillis); |
| } |
| } |
| |
| public void checkServerStatusUsingFakeAccessRequest() throws InterruptedException { |
| RADIUS radiusDummyAccessRequest; |
| // identifier = 1 for fake accessRequest |
| radiusDummyAccessRequest = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, AAA_REQUEST_ID_FAKE_ACCESS_REQUEST); |
| |
| radiusDummyAccessRequest.setIdentifier(AAA_REQUEST_ID_FAKE_ACCESS_REQUEST); |
| radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes()); |
| |
| radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address); |
| radiusDummyAccessRequest.addMessageAuthenticator(secret); |
| setOutTimeInMillis(radiusDummyAccessRequest.getIdentifier()); |
| impl.sendRadiusPacket(radiusDummyAccessRequest, null); |
| synchronized (fakeAccessRequestPacketRecieved) { |
| fakeAccessRequestPacketRecieved.wait(operationalStatusServerTimeoutInMillis); |
| } |
| } |
| |
| public void checkStatusServerForAccessRequestMode() throws InterruptedException { |
| long radiusResponseRecievedTimeDifference = System.currentTimeMillis() - lastRadiusPacketInTimeInMillis; |
| if (radiusResponseRecievedTimeDifference > operationalStatusServerTimeoutInMillis) { |
| checkServerStatusUsingFakeAccessRequest(); |
| if (statusServerReqSent && fakeAccessRequestPacketRecieved) { |
| radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| } else if (statusServerReqSent && !fakeAccessRequestPacketRecieved) { |
| radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE; |
| } else { |
| radiusServerOperationalStatus = OperationalStatus.UNKNOWN; |
| } |
| } else { |
| radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| } |
| } |
| |
| public void checkServerOperationalStatus() { |
| |
| try { |
| if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.STATUS_REQUEST) { |
| // determine operational status by statusServerRequest |
| checkServerStatusUsingStatusServerRequest(); |
| if (statusServerReqSent && serverStatusPacketRecieved) { |
| // if req sent and response recieved |
| radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| } else if (statusServerReqSent && !serverStatusPacketRecieved) { |
| radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE; |
| } else { |
| radiusServerOperationalStatus = OperationalStatus.UNKNOWN; |
| } |
| } else { |
| if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.AUTO) { |
| checkServerStatusUsingStatusServerRequest(); |
| if (statusServerReqSent && serverStatusPacketRecieved) { |
| radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| } else { |
| checkStatusServerForAccessRequestMode(); |
| } |
| } else { |
| checkStatusServerForAccessRequestMode(); |
| } |
| } |
| fakeAccessRequestPacketRecieved = false; |
| serverStatusPacketRecieved = false; |
| } catch (Exception e) { |
| log.error("Caught exception while checking radius server status::" + e); |
| } |
| } |
| |
| /** |
| * Delegate allowing the RadiusOperationalStatus to notify us of events. |
| */ |
| private class InternalRadiusOperationalStatusDelegate implements RadiusOperationalStatusEventDelegate { |
| @Override |
| public void notify(RadiusOperationalStatusEvent radiusOperationalStatusEvent) { |
| log.debug("Radius Operational Status event {} for {}", radiusOperationalStatusEvent.type(), |
| radiusOperationalStatusEvent.subject()); |
| post(radiusOperationalStatusEvent); |
| } |
| } |
| |
| } |