Shubham Sharma | 4900ce6 | 2019-06-19 14:18:50 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017-present Open Networking Foundation |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | package org.opencord.aaa.impl; |
| 17 | |
| 18 | import org.onlab.packet.RADIUS; |
| 19 | import org.onlab.packet.RADIUSAttribute; |
| 20 | import org.onosproject.event.AbstractListenerManager; |
| 21 | import org.opencord.aaa.RadiusCommunicator; |
| 22 | import org.opencord.aaa.RadiusOperationalStatusEvent; |
| 23 | import org.opencord.aaa.RadiusOperationalStatusEventDelegate; |
| 24 | import org.opencord.aaa.RadiusOperationalStatusEventListener; |
| 25 | import org.opencord.aaa.RadiusOperationalStatusService; |
| 26 | import org.osgi.service.component.annotations.Activate; |
| 27 | import org.osgi.service.component.annotations.Component; |
| 28 | import org.osgi.service.component.annotations.Deactivate; |
| 29 | import org.slf4j.Logger; |
| 30 | |
| 31 | import static org.slf4j.LoggerFactory.getLogger; |
| 32 | |
| 33 | @Component(immediate = true) |
| 34 | public class RadiusOperationalStatusManager |
| 35 | extends AbstractListenerManager<RadiusOperationalStatusEvent, RadiusOperationalStatusEventListener> |
| 36 | implements RadiusOperationalStatusService { |
| 37 | |
| 38 | private byte[] address; |
| 39 | private String secret; |
| 40 | private RadiusCommunicator impl; |
| 41 | private RadiusOperationalStatusEventDelegate radiusOprStDelegate; |
| 42 | |
| 43 | private long operationalStatusServerTimeoutInMillis; |
| 44 | private boolean statusServerReqSent; |
| 45 | private final Logger log = getLogger(getClass()); |
| 46 | |
| 47 | private Boolean fakeAccessRequestPacketRecieved = false; |
| 48 | private long fakeAccessRequestOutTimeInMillis; |
| 49 | |
| 50 | private Boolean serverStatusPacketRecieved = false; |
| 51 | private long serverStatusOutTimeInMillis; |
| 52 | |
| 53 | private OperationalStatus radiusServerOperationalStatus; |
| 54 | public static final byte AAA_REQUEST_ID_STATUS_REQUEST = 0; |
| 55 | public static final byte AAA_REQUEST_ID_FAKE_ACCESS_REQUEST = 1; |
| 56 | |
| 57 | private RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode; |
| 58 | |
| 59 | private static final String DUMMY_USER = new String("dummy-user"); |
| 60 | private static final byte RADIUS_CODE_STATUS_REQUEST = (byte) 12; |
| 61 | private long lastRadiusPacketInTimeInMillis; |
| 62 | |
| 63 | public void setOperationalStatusServerTimeoutInMillis(long operationalStatusServerTimeoutInMillis) { |
| 64 | this.operationalStatusServerTimeoutInMillis = operationalStatusServerTimeoutInMillis; |
| 65 | } |
| 66 | |
| 67 | public void setRadiusOperationalStatusEvaluationMode( |
| 68 | RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode) { |
| 69 | this.radiusOperationalStatusEvaluationMode = radiusOperationalStatusEvaluationMode; |
| 70 | } |
| 71 | |
| 72 | public RadiusOperationalStatusEventDelegate getRadiusOprStDelegate() { |
| 73 | return radiusOprStDelegate; |
| 74 | } |
| 75 | |
| 76 | @Override |
| 77 | public void setOutTimeInMillis(byte identifier) { |
| 78 | if (identifier == AAA_REQUEST_ID_STATUS_REQUEST) { |
| 79 | serverStatusOutTimeInMillis = System.currentTimeMillis(); |
| 80 | } else { |
| 81 | fakeAccessRequestOutTimeInMillis = System.currentTimeMillis(); |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | @Override |
| 86 | public String getRadiusServerOperationalStatus() { |
| 87 | return radiusServerOperationalStatus.toString(); |
| 88 | } |
| 89 | |
| 90 | @Activate |
| 91 | public void activate() { |
| 92 | radiusOprStDelegate = new InternalRadiusOperationalStatusDelegate(); |
| 93 | eventDispatcher.addSink(RadiusOperationalStatusEvent.class, listenerRegistry); |
| 94 | radiusServerOperationalStatus = OperationalStatus.UNKNOWN; |
| 95 | } |
| 96 | |
| 97 | public void setStatusServerReqSent(boolean statusServerReqSent) { |
| 98 | this.statusServerReqSent = statusServerReqSent; |
| 99 | } |
| 100 | |
| 101 | @Deactivate |
| 102 | public void deactivate() { |
| 103 | eventDispatcher.removeSink(RadiusOperationalStatusEvent.class); |
| 104 | } |
| 105 | |
| 106 | public void initialize(byte[] address, String secret, RadiusCommunicator impl) { |
| 107 | this.address = address; |
| 108 | this.secret = secret; |
| 109 | this.impl = impl; |
| 110 | } |
| 111 | |
| 112 | public boolean isRadiusResponseForOperationalStatus(byte identifier) { |
| 113 | if (identifier == AAA_REQUEST_ID_STATUS_REQUEST || identifier == AAA_REQUEST_ID_FAKE_ACCESS_REQUEST) { |
| 114 | return true; |
| 115 | } else { |
| 116 | lastRadiusPacketInTimeInMillis = System.currentTimeMillis(); |
| 117 | return false; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | public void handleRadiusPacketForOperationalStatus(RADIUS radiusPacket) { |
| 122 | byte radiusPktIdentifier = radiusPacket.getIdentifier(); |
| 123 | |
| 124 | if (radiusPktIdentifier == AAA_REQUEST_ID_STATUS_REQUEST) { |
| 125 | long serverStatusRttInMillis = System.currentTimeMillis() - serverStatusOutTimeInMillis; |
| 126 | if (serverStatusRttInMillis < operationalStatusServerTimeoutInMillis) { |
| 127 | serverStatusPacketRecieved = true; |
| 128 | } |
| 129 | } else { |
| 130 | long fakeAccessRttInMillis = System.currentTimeMillis() - fakeAccessRequestOutTimeInMillis; |
| 131 | if (fakeAccessRttInMillis < operationalStatusServerTimeoutInMillis) { |
| 132 | fakeAccessRequestPacketRecieved = true; |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | switch (radiusPacket.getCode()) { |
| 137 | case RADIUS.RADIUS_CODE_ACCESS_ACCEPT: |
| 138 | synchronized (serverStatusPacketRecieved) { |
| 139 | serverStatusPacketRecieved.notify(); |
| 140 | } |
| 141 | break; |
| 142 | case RADIUS.RADIUS_CODE_ACCESS_REJECT: |
| 143 | synchronized (fakeAccessRequestPacketRecieved) { |
| 144 | fakeAccessRequestPacketRecieved.notify(); |
| 145 | } |
| 146 | break; |
| 147 | default: |
| 148 | log.warn("Unexpected Radius message for operational status recieved " |
| 149 | + "with code: {}", radiusPacket.getCode()); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | public void checkServerStatusUsingStatusServerRequest() throws InterruptedException { |
| 154 | RADIUS radiusStatusServerRequest; |
| 155 | // identifier = 0 for status server |
| 156 | radiusStatusServerRequest = new RADIUS(RADIUS_CODE_STATUS_REQUEST, AAA_REQUEST_ID_STATUS_REQUEST); |
| 157 | |
| 158 | radiusStatusServerRequest.setIdentifier(AAA_REQUEST_ID_STATUS_REQUEST); |
| 159 | radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes()); |
| 160 | |
| 161 | radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address); |
| 162 | radiusStatusServerRequest.addMessageAuthenticator(secret); |
| 163 | setOutTimeInMillis(radiusStatusServerRequest.getIdentifier()); |
| 164 | impl.sendRadiusPacket(radiusStatusServerRequest, null); |
| 165 | synchronized (serverStatusPacketRecieved) { |
| 166 | serverStatusPacketRecieved.wait(operationalStatusServerTimeoutInMillis); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | public void checkServerStatusUsingFakeAccessRequest() throws InterruptedException { |
| 171 | RADIUS radiusDummyAccessRequest; |
| 172 | // identifier = 1 for fake accessRequest |
| 173 | radiusDummyAccessRequest = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, AAA_REQUEST_ID_FAKE_ACCESS_REQUEST); |
| 174 | |
| 175 | radiusDummyAccessRequest.setIdentifier(AAA_REQUEST_ID_FAKE_ACCESS_REQUEST); |
| 176 | radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes()); |
| 177 | |
| 178 | radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address); |
| 179 | radiusDummyAccessRequest.addMessageAuthenticator(secret); |
| 180 | setOutTimeInMillis(radiusDummyAccessRequest.getIdentifier()); |
| 181 | impl.sendRadiusPacket(radiusDummyAccessRequest, null); |
| 182 | synchronized (fakeAccessRequestPacketRecieved) { |
| 183 | fakeAccessRequestPacketRecieved.wait(operationalStatusServerTimeoutInMillis); |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | public void checkStatusServerForAccessRequestMode() throws InterruptedException { |
| 188 | long radiusResponseRecievedTimeDifference = System.currentTimeMillis() - lastRadiusPacketInTimeInMillis; |
| 189 | if (radiusResponseRecievedTimeDifference > operationalStatusServerTimeoutInMillis) { |
| 190 | checkServerStatusUsingFakeAccessRequest(); |
| 191 | if (statusServerReqSent && fakeAccessRequestPacketRecieved) { |
| 192 | radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| 193 | } else if (statusServerReqSent && !fakeAccessRequestPacketRecieved) { |
| 194 | radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE; |
| 195 | } else { |
| 196 | radiusServerOperationalStatus = OperationalStatus.UNKNOWN; |
| 197 | } |
| 198 | } else { |
| 199 | radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | public void checkServerOperationalStatus() { |
| 204 | |
| 205 | try { |
| 206 | if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.STATUS_REQUEST) { |
| 207 | // determine operational status by statusServerRequest |
| 208 | checkServerStatusUsingStatusServerRequest(); |
| 209 | if (statusServerReqSent && serverStatusPacketRecieved) { |
| 210 | // if req sent and response recieved |
| 211 | radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| 212 | } else if (statusServerReqSent && !serverStatusPacketRecieved) { |
| 213 | radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE; |
| 214 | } else { |
| 215 | radiusServerOperationalStatus = OperationalStatus.UNKNOWN; |
| 216 | } |
| 217 | } else { |
| 218 | if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.AUTO) { |
| 219 | checkServerStatusUsingStatusServerRequest(); |
| 220 | if (statusServerReqSent && serverStatusPacketRecieved) { |
| 221 | radiusServerOperationalStatus = OperationalStatus.IN_USE; |
| 222 | } else { |
| 223 | checkStatusServerForAccessRequestMode(); |
| 224 | } |
| 225 | } else { |
| 226 | checkStatusServerForAccessRequestMode(); |
| 227 | } |
| 228 | } |
| 229 | fakeAccessRequestPacketRecieved = false; |
| 230 | serverStatusPacketRecieved = false; |
| 231 | } catch (Exception e) { |
| 232 | log.error("Caught exception while checking radius server status::" + e); |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | /** |
| 237 | * Delegate allowing the RadiusOperationalStatus to notify us of events. |
| 238 | */ |
| 239 | private class InternalRadiusOperationalStatusDelegate implements RadiusOperationalStatusEventDelegate { |
| 240 | @Override |
| 241 | public void notify(RadiusOperationalStatusEvent radiusOperationalStatusEvent) { |
| 242 | log.debug("Radius Operational Status event {} for {}", radiusOperationalStatusEvent.type(), |
| 243 | radiusOperationalStatusEvent.subject()); |
| 244 | post(radiusOperationalStatusEvent); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | } |