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