blob: a0746207336e49c20e90ef2938b57df149dff446 [file] [log] [blame]
Ray Milkey17481412015-12-09 09:16:26 -08001/*
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07002 * Copyright 2021-present Open Networking Foundation
Ray Milkey17481412015-12-09 09:16:26 -08003 *
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 */
alshabib36a4d732016-06-01 16:03:59 -070016package org.opencord.olt.rest;
Ray Milkey17481412015-12-09 09:16:26 -080017
Gustavo Silva29fb20e2022-05-26 09:59:54 -030018import com.fasterxml.jackson.databind.node.ArrayNode;
19import com.fasterxml.jackson.databind.node.ObjectNode;
Amit Ghoshe1d3f092018-10-09 19:44:33 +010020import org.onlab.packet.VlanId;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010021import org.onosproject.net.ConnectPoint;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.PortNumber;
24import org.onosproject.rest.AbstractWebResource;
25import org.opencord.olt.AccessDeviceService;
Gustavo Silva29fb20e2022-05-26 09:59:54 -030026import org.opencord.olt.OltFlowServiceInterface;
27import org.opencord.olt.ServiceKey;
28import org.opencord.sadis.UniTagInformation;
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010029
Gustavo Silva29fb20e2022-05-26 09:59:54 -030030import org.slf4j.Logger;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000031import javax.ws.rs.Consumes;
Ray Milkey17481412015-12-09 09:16:26 -080032import javax.ws.rs.DELETE;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070033import javax.ws.rs.GET;
Ray Milkey17481412015-12-09 09:16:26 -080034import javax.ws.rs.POST;
35import javax.ws.rs.Path;
36import javax.ws.rs.PathParam;
37import javax.ws.rs.Produces;
38import javax.ws.rs.core.MediaType;
39import javax.ws.rs.core.Response;
40
Gustavo Silva29fb20e2022-05-26 09:59:54 -030041import java.util.Map;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070042import java.util.Optional;
Gustavo Silva29fb20e2022-05-26 09:59:54 -030043import java.util.Set;
44import java.util.stream.Collectors;
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070045
Andrea Campanellacbbb7952019-11-25 06:38:41 +000046import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
Andrea Campanella51118232021-07-01 17:18:02 +020047import static org.slf4j.LoggerFactory.getLogger;
Amit Ghosh31939522018-08-16 13:28:21 +010048
Ray Milkey17481412015-12-09 09:16:26 -080049/**
50 * OLT REST APIs.
51 */
52
53@Path("oltapp")
54public class OltWebResource extends AbstractWebResource {
Gustavo Silva29fb20e2022-05-26 09:59:54 -030055 private final ObjectNode root = mapper().createObjectNode();
56 private final ArrayNode node = root.putArray("entries");
Andrea Campanella51118232021-07-01 17:18:02 +020057 private final Logger log = getLogger(getClass());
Gustavo Silva29fb20e2022-05-26 09:59:54 -030058 private static final String LOCATION = "location";
59 private static final String TAG_INFO = "tagInfo";
Andrea Campanella51118232021-07-01 17:18:02 +020060
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070061 @GET
62 @Produces(MediaType.APPLICATION_JSON)
63 @Path("status")
64 public Response status() {
65 return Response.ok().build();
66 }
Ray Milkey17481412015-12-09 09:16:26 -080067 /**
68 * Provision a subscriber.
69 *
Jian Lid8bca082016-01-22 16:46:58 -080070 * @param device device id
71 * @param port port number
Andrea Campanellacbbb7952019-11-25 06:38:41 +000072 * @return 200 OK or 500 Internal Server Error
Ray Milkey17481412015-12-09 09:16:26 -080073 */
74 @POST
75 @Produces(MediaType.APPLICATION_JSON)
Amit Ghosh1ed9aef2018-07-17 17:08:16 +010076 @Path("{device}/{port}")
Ray Milkey17481412015-12-09 09:16:26 -080077 public Response provisionSubscriber(
Andrea Campanellacbbb7952019-11-25 06:38:41 +000078 @PathParam("device") String device,
79 @PathParam("port") long port) {
Ray Milkey17481412015-12-09 09:16:26 -080080 AccessDeviceService service = get(AccessDeviceService.class);
81 DeviceId deviceId = DeviceId.deviceId(device);
82 PortNumber portNumber = PortNumber.portNumber(port);
Ray Milkey17481412015-12-09 09:16:26 -080083 ConnectPoint connectPoint = new ConnectPoint(deviceId, portNumber);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -070084
Andrea Campanellacbbb7952019-11-25 06:38:41 +000085 try {
86 service.provisionSubscriber(connectPoint);
87 } catch (Exception e) {
Andrea Campanella51118232021-07-01 17:18:02 +020088 log.error("Can't provision subscriber {} due to exception", connectPoint, e);
89 return Response.status(INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
Andrea Campanellacbbb7952019-11-25 06:38:41 +000090 }
Ray Milkey17481412015-12-09 09:16:26 -080091 return ok("").build();
92 }
93
94 /**
95 * Remove the provisioning for a subscriber.
Jian Lid8bca082016-01-22 16:46:58 -080096 *
97 * @param device device id
98 * @param port port number
Jian Lic39f08d2016-05-10 11:48:19 -070099 * @return 204 NO CONTENT
Ray Milkey17481412015-12-09 09:16:26 -0800100 */
101 @DELETE
Ray Milkey17481412015-12-09 09:16:26 -0800102 @Path("{device}/{port}")
103 public Response removeSubscriber(
104 @PathParam("device")String device,
105 @PathParam("port")long port) {
106 AccessDeviceService service = get(AccessDeviceService.class);
107 DeviceId deviceId = DeviceId.deviceId(device);
108 PortNumber portNumber = PortNumber.portNumber(port);
109 ConnectPoint connectPoint = new ConnectPoint(deviceId, portNumber);
Andrea Campanella51118232021-07-01 17:18:02 +0200110 try {
111 service.removeSubscriber(connectPoint);
112 } catch (Exception e) {
113 log.error("Can't remove subscriber {} due to exception", connectPoint, e);
114 return Response.status(INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
115 }
Jian Lic39f08d2016-05-10 11:48:19 -0700116 return Response.noContent().build();
Ray Milkey17481412015-12-09 09:16:26 -0800117 }
Amit Ghosh31939522018-08-16 13:28:21 +0100118
119 /**
120 * Provision service for a subscriber.
121 *
122 * @param portName Name of the port on which the subscriber is connected
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000123 * @return 200 OK or 204 NO CONTENT
Amit Ghosh31939522018-08-16 13:28:21 +0100124 */
125 @POST
126 @Produces(MediaType.APPLICATION_JSON)
127 @Path("services/{portName}")
128 public Response provisionServices(
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000129 @PathParam("portName") String portName) {
Amit Ghosh31939522018-08-16 13:28:21 +0100130 AccessDeviceService service = get(AccessDeviceService.class);
131
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100132 Optional<VlanId> emptyVlan = Optional.empty();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000133 Optional<Integer> emptyTpId = Optional.empty();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700134 // Check if we can find the connect point to which this subscriber is connected
135 ConnectPoint cp = service.findSubscriberConnectPoint(portName);
136 if (cp == null) {
137 log.warn("ConnectPoint not found for {}", portName);
138 return Response.status(INTERNAL_SERVER_ERROR)
139 .entity("ConnectPoint not found for " + portName).build();
140 }
141 if (service.provisionSubscriber(cp)) {
142 return ok("").build();
143 }
144 return Response.noContent().build();
145 }
146
147 /**
148 * Removes services for a subscriber.
149 *
150 * @param portName Name of the port on which the subscriber is connected
151 * @return 200 OK or 204 NO CONTENT
152 */
153 @DELETE
154 @Produces(MediaType.APPLICATION_JSON)
155 @Path("services/{portName}")
156 public Response deleteServices(
157 @PathParam("portName") String portName) {
158 AccessDeviceService service = get(AccessDeviceService.class);
159
160 ConnectPoint cp = service.findSubscriberConnectPoint(portName);
161 if (cp == null) {
162 log.warn("ConnectPoint not found for {}", portName);
163 return Response.status(INTERNAL_SERVER_ERROR)
164 .entity("ConnectPoint not found for " + portName).build();
165 }
166 if (service.removeSubscriber(cp)) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100167 return ok("").build();
168 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000169 return Response.noContent().build();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100170 }
171
172 /**
173 * Provision service with particular tags for a subscriber.
174 *
175 * @param portName Name of the port on which the subscriber is connected
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000176 * @param sTagVal additional outer tag on this port
177 * @param cTagVal additional innter tag on this port
178 * @param tpIdVal technology profile id
179 * @return 200 OK or 204 NO CONTENT
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100180 */
181 @POST
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000182 @Consumes(MediaType.APPLICATION_JSON)
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100183 @Produces(MediaType.APPLICATION_JSON)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000184 @Path("services/{portName}/{sTag}/{cTag}/{tpId}")
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100185 public Response provisionAdditionalVlans(
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000186 @PathParam("portName") String portName,
187 @PathParam("sTag") String sTagVal,
188 @PathParam("cTag") String cTagVal,
189 @PathParam("tpId") String tpIdVal) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100190 AccessDeviceService service = get(AccessDeviceService.class);
191 VlanId cTag = VlanId.vlanId(cTagVal);
192 VlanId sTag = VlanId.vlanId(sTagVal);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000193 Integer tpId = Integer.valueOf(tpIdVal);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700194 // TODO this is not optimal, because we call device service 2 times here and
195 // 2 times in the provisionSubscriber call, optimize byu having 2 more methods
196 // in the OltService that allow provisioning with portName.
197 ConnectPoint cp = service.findSubscriberConnectPoint(portName);
198 if (cp == null) {
199 log.warn("ConnectPoint not found for {}", portName);
200 return Response.status(INTERNAL_SERVER_ERROR)
201 .entity("ConnectPoint not found for " + portName).build();
Amit Ghosh31939522018-08-16 13:28:21 +0100202 }
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700203 if (service.provisionSubscriber(cp, cTag, sTag, tpId)) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100204 return ok("").build();
205 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000206 return Response.noContent().build();
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100207 }
208
209 /**
210 * Removes additional vlans of a particular subscriber.
211 *
212 * @param portName Name of the port on which the subscriber is connected
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000213 * @param sTagVal additional outer tag on this port which needs to be removed
214 * @param cTagVal additional inner tag on this port which needs to be removed
215 * @param tpIdVal additional technology profile id
216 * @return 200 OK or 204 NO CONTENT
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100217 */
218 @DELETE
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000219 @Consumes(MediaType.APPLICATION_JSON)
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100220 @Produces(MediaType.APPLICATION_JSON)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000221 @Path("services/{portName}/{sTag}/{cTag}/{tpId}")
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100222 public Response removeAdditionalVlans(
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000223 @PathParam("portName") String portName,
224 @PathParam("sTag") String sTagVal,
225 @PathParam("cTag") String cTagVal,
226 @PathParam("tpId") String tpIdVal) {
Amit Ghoshe1d3f092018-10-09 19:44:33 +0100227 AccessDeviceService service = get(AccessDeviceService.class);
228 VlanId cTag = VlanId.vlanId(cTagVal);
229 VlanId sTag = VlanId.vlanId(sTagVal);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000230 Integer tpId = Integer.valueOf(tpIdVal);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -0700231 // TODO this is not optimal, because we call device service 2 times here and
232 // 2 times in the provisionSubscriber call, optimize byu having 2 more methods
233 // in the OltService that allow provisioning with portName.
234 ConnectPoint cp = service.findSubscriberConnectPoint(portName);
235 if (cp == null) {
236 log.warn("ConnectPoint not found for {}", portName);
237 return Response.status(INTERNAL_SERVER_ERROR)
238 .entity("ConnectPoint not found for " + portName).build();
239 }
240 if (service.removeSubscriber(cp, cTag, sTag, tpId)) {
Amit Ghosh31939522018-08-16 13:28:21 +0100241 return ok("").build();
242 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000243 return Response.noContent().build();
Amit Ghosh31939522018-08-16 13:28:21 +0100244 }
Gustavo Silva29fb20e2022-05-26 09:59:54 -0300245
246 /**
247 * Gets subscribers programmed in the dataplane.
248 *
249 * @return 200 OK
250 */
251 @GET
252 @Path("programmed-subscribers")
253 @Produces(MediaType.APPLICATION_JSON)
254 public Response getProgrammedSubscribers() {
255 return getProgrammedSubscribers(null, null);
256 }
257
258 /**
259 * Gets subscribers programmed in the dataplane.
260 *
261 * @param deviceId device-id to filter the results.
262 *
263 * @return 200 OK
264 */
265 @GET
266 @Path("programmed-subscribers/{deviceId}")
267 @Produces(MediaType.APPLICATION_JSON)
268 public Response getProgrammedSubscribersByDeviceId(@PathParam("deviceId") String deviceId) {
269 return getProgrammedSubscribers(deviceId, null);
270 }
271
272 /*
273 * Gets subscribers programmed in the dataplane.
274 *
275 * @param deviceId device-id to filter the results.
276 * @param port port to filter the results.
277 *
278 * @return 200 OK
279 */
280 @GET
281 @Path("programmed-subscribers/{deviceId}/{port}")
282 @Produces(MediaType.APPLICATION_JSON)
283 public Response getProgrammedSubscribersByConnectPoint(@PathParam("deviceId") String deviceId,
284 @PathParam("port") String port) {
285 return getProgrammedSubscribers(deviceId, port);
286 }
287
288 private Response getProgrammedSubscribers(String deviceId, String port) {
289 OltFlowServiceInterface service = get(OltFlowServiceInterface.class);
290 Map<ServiceKey, UniTagInformation> info = service.getProgrammedSubscribers();
291 Set<Map.Entry<ServiceKey, UniTagInformation>> entries = info.entrySet();
292 if (deviceId != null && !deviceId.isEmpty()) {
293 entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().deviceId()
294 .equals(DeviceId.deviceId(deviceId))).collect(Collectors.toSet());
295 }
296
297 if (port != null && !port.isEmpty()) {
298 PortNumber portNumber = PortNumber.portNumber(port);
299 entries = entries.stream().filter(entry -> entry.getKey().getPort().connectPoint().port()
300 .equals(portNumber)).collect(Collectors.toSet());
301 }
302
303 try {
304 entries.forEach(entry -> {
305 ConnectPoint location = entry.getKey().getPort().connectPoint();
306 UniTagInformation tagInfo = entry.getValue();
307 ObjectNode encodedTagInfo = codec(UniTagInformation.class).encode(tagInfo, this);
308 ObjectNode encodedEntry = mapper().createObjectNode();
309 encodedEntry.put(LOCATION, location.toString())
310 .set(TAG_INFO, encodedTagInfo);
311 node.add(encodedEntry);
312 });
313
314 return ok(mapper().writeValueAsString(root)).build();
315 } catch (Exception e) {
316 log.error("Error while fetching programmed subscriber list through REST API: {}", e.getMessage());
317 return Response.status(INTERNAL_SERVER_ERROR).build();
318 }
319 }
Ray Milkey17481412015-12-09 09:16:26 -0800320}