blob: 77e58c0473faad264aa10d9bfbbf13da83201391 [file] [log] [blame]
/*
* Copyright 2017-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opencord.aaa.impl;
import org.onlab.packet.RADIUS;
import org.onlab.packet.RADIUSAttribute;
import org.onosproject.event.AbstractListenerManager;
import org.opencord.aaa.RadiusCommunicator;
import org.opencord.aaa.RadiusOperationalStatusEvent;
import org.opencord.aaa.RadiusOperationalStatusEventDelegate;
import org.opencord.aaa.RadiusOperationalStatusEventListener;
import org.opencord.aaa.RadiusOperationalStatusService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
@Component(immediate = true)
public class RadiusOperationalStatusManager
extends AbstractListenerManager<RadiusOperationalStatusEvent, RadiusOperationalStatusEventListener>
implements RadiusOperationalStatusService {
private byte[] address;
private String secret;
private RadiusCommunicator impl;
private RadiusOperationalStatusEventDelegate radiusOprStDelegate;
private long operationalStatusServerTimeoutInMillis;
private boolean statusServerReqSent;
private final Logger log = getLogger(getClass());
private Boolean fakeAccessRequestPacketRecieved = false;
private long fakeAccessRequestOutTimeInMillis;
private Boolean serverStatusPacketRecieved = false;
private long serverStatusOutTimeInMillis;
private OperationalStatus radiusServerOperationalStatus;
public static final byte AAA_REQUEST_ID_STATUS_REQUEST = 0;
public static final byte AAA_REQUEST_ID_FAKE_ACCESS_REQUEST = 1;
private RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode;
// FIXME the DUMMY_USER should be read from config (or netcfg)
private static final String DUMMY_USER = new String("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);
}
}
}