blob: 2fe5755ff35cb68882d8dbf10ef90b77eea9eb4d [file] [log] [blame]
Shubham Sharma4900ce62019-06-19 14:18:50 +00001/*
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 */
16package org.opencord.aaa.impl;
17
18import org.onlab.packet.RADIUS;
19import org.onlab.packet.RADIUSAttribute;
20import org.onosproject.event.AbstractListenerManager;
21import org.opencord.aaa.RadiusCommunicator;
22import org.opencord.aaa.RadiusOperationalStatusEvent;
23import org.opencord.aaa.RadiusOperationalStatusEventDelegate;
24import org.opencord.aaa.RadiusOperationalStatusEventListener;
25import org.opencord.aaa.RadiusOperationalStatusService;
26import org.osgi.service.component.annotations.Activate;
27import org.osgi.service.component.annotations.Component;
28import org.osgi.service.component.annotations.Deactivate;
29import org.slf4j.Logger;
30
31import static org.slf4j.LoggerFactory.getLogger;
32
33@Component(immediate = true)
34public 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}