blob: 377cd0ab2244763ec935648eac258338523f0ff7 [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;
Matteo Scandoloe033c262020-10-14 11:37:39 -070054
Shubham Sharma4900ce62019-06-19 14:18:50 +000055 public static final byte AAA_REQUEST_ID_STATUS_REQUEST = 0;
56 public static final byte AAA_REQUEST_ID_FAKE_ACCESS_REQUEST = 1;
57
58 private RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode;
59
Andrea Campanellac4781e62020-10-08 12:58:45 +020060 // FIXME the DUMMY_USER should be read from config (or netcfg)
61 private static final String DUMMY_USER = new String("user");
Shubham Sharma4900ce62019-06-19 14:18:50 +000062 private static final byte RADIUS_CODE_STATUS_REQUEST = (byte) 12;
63 private long lastRadiusPacketInTimeInMillis;
64
65 public void setOperationalStatusServerTimeoutInMillis(long operationalStatusServerTimeoutInMillis) {
66 this.operationalStatusServerTimeoutInMillis = operationalStatusServerTimeoutInMillis;
67 }
68
69 public void setRadiusOperationalStatusEvaluationMode(
70 RadiusOperationalStatusEvaluationMode radiusOperationalStatusEvaluationMode) {
71 this.radiusOperationalStatusEvaluationMode = radiusOperationalStatusEvaluationMode;
72 }
73
74 public RadiusOperationalStatusEventDelegate getRadiusOprStDelegate() {
75 return radiusOprStDelegate;
76 }
77
78 @Override
79 public void setOutTimeInMillis(byte identifier) {
80 if (identifier == AAA_REQUEST_ID_STATUS_REQUEST) {
81 serverStatusOutTimeInMillis = System.currentTimeMillis();
82 } else {
83 fakeAccessRequestOutTimeInMillis = System.currentTimeMillis();
84 }
85 }
86
87 @Override
88 public String getRadiusServerOperationalStatus() {
89 return radiusServerOperationalStatus.toString();
90 }
91
92 @Activate
93 public void activate() {
94 radiusOprStDelegate = new InternalRadiusOperationalStatusDelegate();
95 eventDispatcher.addSink(RadiusOperationalStatusEvent.class, listenerRegistry);
96 radiusServerOperationalStatus = OperationalStatus.UNKNOWN;
97 }
98
99 public void setStatusServerReqSent(boolean statusServerReqSent) {
100 this.statusServerReqSent = statusServerReqSent;
101 }
102
103 @Deactivate
104 public void deactivate() {
105 eventDispatcher.removeSink(RadiusOperationalStatusEvent.class);
106 }
107
108 public void initialize(byte[] address, String secret, RadiusCommunicator impl) {
109 this.address = address;
110 this.secret = secret;
111 this.impl = impl;
112 }
113
114 public boolean isRadiusResponseForOperationalStatus(byte identifier) {
115 if (identifier == AAA_REQUEST_ID_STATUS_REQUEST || identifier == AAA_REQUEST_ID_FAKE_ACCESS_REQUEST) {
116 return true;
117 } else {
118 lastRadiusPacketInTimeInMillis = System.currentTimeMillis();
119 return false;
120 }
121 }
122
123 public void handleRadiusPacketForOperationalStatus(RADIUS radiusPacket) {
124 byte radiusPktIdentifier = radiusPacket.getIdentifier();
125
126 if (radiusPktIdentifier == AAA_REQUEST_ID_STATUS_REQUEST) {
127 long serverStatusRttInMillis = System.currentTimeMillis() - serverStatusOutTimeInMillis;
128 if (serverStatusRttInMillis < operationalStatusServerTimeoutInMillis) {
129 serverStatusPacketRecieved = true;
130 }
131 } else {
132 long fakeAccessRttInMillis = System.currentTimeMillis() - fakeAccessRequestOutTimeInMillis;
133 if (fakeAccessRttInMillis < operationalStatusServerTimeoutInMillis) {
134 fakeAccessRequestPacketRecieved = true;
135 }
136 }
137
138 switch (radiusPacket.getCode()) {
139 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
140 synchronized (serverStatusPacketRecieved) {
141 serverStatusPacketRecieved.notify();
142 }
143 break;
144 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
145 synchronized (fakeAccessRequestPacketRecieved) {
146 fakeAccessRequestPacketRecieved.notify();
147 }
148 break;
149 default:
150 log.warn("Unexpected Radius message for operational status recieved "
151 + "with code: {}", radiusPacket.getCode());
152 }
153 }
154
155 public void checkServerStatusUsingStatusServerRequest() throws InterruptedException {
156 RADIUS radiusStatusServerRequest;
157 // identifier = 0 for status server
158 radiusStatusServerRequest = new RADIUS(RADIUS_CODE_STATUS_REQUEST, AAA_REQUEST_ID_STATUS_REQUEST);
159
160 radiusStatusServerRequest.setIdentifier(AAA_REQUEST_ID_STATUS_REQUEST);
161 radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes());
162
163 radiusStatusServerRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address);
164 radiusStatusServerRequest.addMessageAuthenticator(secret);
165 setOutTimeInMillis(radiusStatusServerRequest.getIdentifier());
166 impl.sendRadiusPacket(radiusStatusServerRequest, null);
167 synchronized (serverStatusPacketRecieved) {
168 serverStatusPacketRecieved.wait(operationalStatusServerTimeoutInMillis);
169 }
170 }
171
172 public void checkServerStatusUsingFakeAccessRequest() throws InterruptedException {
173 RADIUS radiusDummyAccessRequest;
174 // identifier = 1 for fake accessRequest
175 radiusDummyAccessRequest = new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST, AAA_REQUEST_ID_FAKE_ACCESS_REQUEST);
176
177 radiusDummyAccessRequest.setIdentifier(AAA_REQUEST_ID_FAKE_ACCESS_REQUEST);
178 radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME, DUMMY_USER.getBytes());
179
180 radiusDummyAccessRequest.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP, address);
181 radiusDummyAccessRequest.addMessageAuthenticator(secret);
182 setOutTimeInMillis(radiusDummyAccessRequest.getIdentifier());
183 impl.sendRadiusPacket(radiusDummyAccessRequest, null);
184 synchronized (fakeAccessRequestPacketRecieved) {
185 fakeAccessRequestPacketRecieved.wait(operationalStatusServerTimeoutInMillis);
186 }
187 }
188
189 public void checkStatusServerForAccessRequestMode() throws InterruptedException {
190 long radiusResponseRecievedTimeDifference = System.currentTimeMillis() - lastRadiusPacketInTimeInMillis;
191 if (radiusResponseRecievedTimeDifference > operationalStatusServerTimeoutInMillis) {
192 checkServerStatusUsingFakeAccessRequest();
193 if (statusServerReqSent && fakeAccessRequestPacketRecieved) {
194 radiusServerOperationalStatus = OperationalStatus.IN_USE;
195 } else if (statusServerReqSent && !fakeAccessRequestPacketRecieved) {
196 radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE;
197 } else {
198 radiusServerOperationalStatus = OperationalStatus.UNKNOWN;
199 }
200 } else {
201 radiusServerOperationalStatus = OperationalStatus.IN_USE;
202 }
203 }
204
205 public void checkServerOperationalStatus() {
206
207 try {
208 if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.STATUS_REQUEST) {
209 // determine operational status by statusServerRequest
210 checkServerStatusUsingStatusServerRequest();
211 if (statusServerReqSent && serverStatusPacketRecieved) {
212 // if req sent and response recieved
213 radiusServerOperationalStatus = OperationalStatus.IN_USE;
214 } else if (statusServerReqSent && !serverStatusPacketRecieved) {
215 radiusServerOperationalStatus = OperationalStatus.UNAVAILABLE;
216 } else {
217 radiusServerOperationalStatus = OperationalStatus.UNKNOWN;
218 }
219 } else {
220 if (radiusOperationalStatusEvaluationMode == RadiusOperationalStatusEvaluationMode.AUTO) {
221 checkServerStatusUsingStatusServerRequest();
222 if (statusServerReqSent && serverStatusPacketRecieved) {
223 radiusServerOperationalStatus = OperationalStatus.IN_USE;
224 } else {
225 checkStatusServerForAccessRequestMode();
226 }
227 } else {
228 checkStatusServerForAccessRequestMode();
229 }
230 }
231 fakeAccessRequestPacketRecieved = false;
232 serverStatusPacketRecieved = false;
233 } catch (Exception e) {
234 log.error("Caught exception while checking radius server status::" + e);
235 }
236 }
237
238 /**
239 * Delegate allowing the RadiusOperationalStatus to notify us of events.
240 */
241 private class InternalRadiusOperationalStatusDelegate implements RadiusOperationalStatusEventDelegate {
242 @Override
243 public void notify(RadiusOperationalStatusEvent radiusOperationalStatusEvent) {
244 log.debug("Radius Operational Status event {} for {}", radiusOperationalStatusEvent.type(),
245 radiusOperationalStatusEvent.subject());
246 post(radiusOperationalStatusEvent);
247 }
248 }
249
250}