blob: 1e2576665101314eee9cfddf4bab607177b8c0c7 [file] [log] [blame]
Tunahan Sezen03e55272020-04-18 09:18:53 +00001/*
Joey Armstrong53fcac22023-01-11 13:25:01 -05002 * Copyright 2017-2023 Open Networking Foundation (ONF) and the ONF Contributors
Tunahan Sezen03e55272020-04-18 09:18:53 +00003 *
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.maclearner.app.rest;
17
18import com.fasterxml.jackson.databind.ObjectMapper;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.PortNumber;
25import org.onosproject.rest.AbstractWebResource;
26import org.opencord.maclearner.api.DefaultMacLearner;
27import org.opencord.maclearner.api.MacDeleteResult;
28import org.opencord.maclearner.api.MacLearnerKey;
29import org.opencord.maclearner.api.MacLearnerService;
30import org.slf4j.Logger;
31
32import javax.ws.rs.DELETE;
33import javax.ws.rs.GET;
34import 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;
40import java.net.URI;
41import java.net.URISyntaxException;
42import java.util.Map;
43import java.util.Optional;
44import java.util.Set;
45
Tunahan Sezen1f65c902020-09-08 13:10:16 +000046import static javax.ws.rs.core.Response.Status.NO_CONTENT;
47import static javax.ws.rs.core.Response.Status.OK;
Tunahan Sezen03e55272020-04-18 09:18:53 +000048import static org.slf4j.LoggerFactory.getLogger;
Tunahan Sezen03e55272020-04-18 09:18:53 +000049
50/**
51 * Mac Learner web resource.
52 */
53@Path("maclearner")
54public class MacLearnerWebResource extends AbstractWebResource {
55
56 MacLearnerCodec codec = new MacLearnerCodec();
57
58 private final MacLearnerService macLearnerService = get(MacLearnerService.class);
59
60 private final Logger log = getLogger(getClass());
61
62 private static final String INVALID_PATH_PARAMETERS = "Invalid path parameters";
63 private static final String PATH_DELIMITER = "/";
64
65 /**
66 * Get all MAC Mappings.
67 *
68 * @return list of MAC Mapping json object with deviceId, portNumber, vlanId, macAddress fields
69 */
70 @GET
71 @Path("/mapping/all")
72 @Produces(MediaType.APPLICATION_JSON)
73 public Response getAllMappings() {
74 Map<MacLearnerKey, MacAddress> macMappings = macLearnerService.getAllMappings();
75 ObjectMapper mapper = new ObjectMapper();
76 ObjectNode root = mapper.createObjectNode();
77 ArrayNode macArray = mapper.createArrayNode();
78 if (macMappings == null) {
79 root.set("data", macArray);
80 return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
81 } else {
82 macMappings.forEach((k, v) -> macArray.add(
83 codec.encode(new DefaultMacLearner(k.getDeviceId(),
84 k.getPortNumber(),
85 k.getVlanId(),
86 v), this)
87 ));
88 }
89 root.set("data", macArray);
90 return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
91 }
92
93 /**
94 * Get MAC Mapping for request paramaters.
95 *
96 * @param ofDeviceId device id
97 * @param portNumber port number
98 * @param vlanId vlan id
99 * @return MAC Address json object with macAddress field
100 * 204 NO_CONTENT if it does not exist
101 */
102 @GET
103 @Path("/mapping/{ofDeviceId}/{portNumber}/{vlanId}")
104 @Produces(MediaType.APPLICATION_JSON)
105 public Response getMacMapping(@PathParam("ofDeviceId") String ofDeviceId,
106 @PathParam("portNumber") Integer portNumber,
107 @PathParam("vlanId") Short vlanId) {
108 Optional<MacAddress> mac = macLearnerService.getMacMapping(DeviceId.deviceId(ofDeviceId),
109 PortNumber.portNumber(portNumber),
110 VlanId.vlanId(vlanId));
111 if (mac.isEmpty()) {
112 log.warn("MAC Address not found for: ofDeviceId:{} portNumber:{} vlanId:{}",
113 ofDeviceId, portNumber, vlanId);
114 return Response.status(NO_CONTENT).build();
115 }
116 ObjectMapper mapper = new ObjectMapper();
117 ObjectNode root = mapper.createObjectNode();
118 root.set("data", codec.encodeMac(mac.get(), this));
119 return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).status(OK).build();
120 }
121
122 /**
123 * Delete MAC Mapping for request paramaters.
124 *
125 * @param ofDeviceId device id
126 * @param portNumber port number
127 * @param vlanId vlan id
128 * @return URI of request
129 */
130 @DELETE
131 @Path("/mapping/{ofDeviceId}/{portNumber}/{vlanId}")
132 @Produces(MediaType.APPLICATION_JSON)
133 public Response deleteMacMapping(@PathParam("ofDeviceId") String ofDeviceId,
134 @PathParam("portNumber") Integer portNumber,
135 @PathParam("vlanId") Short vlanId) {
136 try {
137 if (ofDeviceId == null || portNumber == null || vlanId == null) {
138 throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
139 }
140 MacDeleteResult deleteResult = macLearnerService.deleteMacMapping(DeviceId.deviceId(ofDeviceId),
141 PortNumber.portNumber(portNumber),
142 VlanId.vlanId(vlanId));
143 if (deleteResult.equals(MacDeleteResult.UNSUCCESSFUL)) {
144 return Response.status(NO_CONTENT).build();
145 }
146 return Response
147 .created(new URI("/delete/mapping/" +
148 ofDeviceId + PATH_DELIMITER +
149 portNumber + PATH_DELIMITER +
150 vlanId))
151 .status(OK)
152 .build();
153 } catch (URISyntaxException e) {
154 log.error("URI Syntax Exception occurred while deleting MAC Mapping " +
155 "for deviceId: {} portNumber: {} vlanId: {}",
156 ofDeviceId, portNumber, vlanId, e);
157 return Response.serverError().build();
158 }
159 }
160
161 /**
162 * Delete MAC Mappings for specific port of a device.
163 *
164 * @param ofDeviceId device id
165 * @param portNumber port number
166 * @return URI of request
167 */
168 @DELETE
169 @Path("/mappings/{ofDeviceId}/{portNumber}")
170 @Produces(MediaType.APPLICATION_JSON)
171 public Response deleteMacMappings(@PathParam("ofDeviceId") String ofDeviceId,
172 @PathParam("portNumber") Integer portNumber) {
173 try {
174 if (ofDeviceId == null || portNumber == null) {
175 throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
176 }
177 boolean deleteSuccess = macLearnerService.deleteMacMappings(DeviceId.deviceId(ofDeviceId),
178 PortNumber.portNumber(portNumber));
179 if (!deleteSuccess) {
180 return Response.status(NO_CONTENT).build();
181 }
182 return Response.created(new URI("/delete/mappings/" +
183 ofDeviceId + PATH_DELIMITER +
184 portNumber)).status(OK).build();
185 } catch (URISyntaxException e) {
186 log.error("URI Syntax Exception occurred while deleting MAC Mappings for deviceId: {} portNumber: {}",
187 ofDeviceId, portNumber, e);
188 return Response.serverError().build();
189 }
190 }
191
192 /**
193 * Get ignored ports for MAC Mapping.
194 *
195 * @return list of ignored port json object with deviceId and portNumber fields
196 */
197 @GET
198 @Path("/ports/ignored")
199 @Produces(MediaType.APPLICATION_JSON)
200 public Response getIgnoredPorts() {
201 Map<DeviceId, Set<PortNumber>> ignoredPorts = macLearnerService.getIgnoredPorts();
202 ObjectMapper mapper = new ObjectMapper();
203 ObjectNode root = mapper.createObjectNode();
204 ArrayNode ignoredPortsArray = mapper.createArrayNode();
205 if (ignoredPorts == null) {
206 root.set("data", ignoredPortsArray);
207 return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
208 } else {
209 for (Map.Entry<DeviceId, Set<PortNumber>> entry : ignoredPorts.entrySet()) {
210 entry.getValue().forEach(portNumber -> ignoredPortsArray.add(
211 codec.encodePort(new MacLearnerKey(entry.getKey(), portNumber, VlanId.NONE), this)
212 ));
213 }
214 }
215 root.set("data", ignoredPortsArray);
216 return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
217 }
218
219 /**
220 * Add to ignore ports map.
221 *
222 * @param ofDeviceId deviceId
223 * @param portNumber portNumber
224 * @return URI of request
225 */
226 @POST
227 @Path("/ignore-port/{ofDeviceId}/{portNumber}")
228 @Produces(MediaType.APPLICATION_JSON)
229 public Response addPortToIgnore(@PathParam("ofDeviceId") String ofDeviceId,
230 @PathParam("portNumber") Integer portNumber) {
231 try {
232 if (ofDeviceId == null || portNumber == null) {
233 throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
234 }
235 macLearnerService.addPortToIgnore(DeviceId.deviceId(ofDeviceId),
236 PortNumber.portNumber(portNumber));
237 return Response.created(new URI("/add/ignore-port/" +
238 ofDeviceId + PATH_DELIMITER +
239 portNumber)).status(OK).build();
240 } catch (URISyntaxException e) {
241 log.error("URI Syntax Exception occurred while adding ignore port deviceId: {} portNumber {}",
242 ofDeviceId, portNumber, e);
243 return Response.serverError().build();
244 }
245 }
246
247 /**
248 * Remove from ignored ports map.
249 *
250 * @param ofDeviceId device id
251 * @param portNumber port number
252 * @return URI of request
253 */
254 @DELETE
255 @Path("/ignore-port/{ofDeviceId}/{portNumber}")
256 @Produces(MediaType.APPLICATION_JSON)
257 public Response removeFromIgnoredPorts(@PathParam("ofDeviceId") String ofDeviceId,
258 @PathParam("portNumber") Integer portNumber) {
259 try {
260 if (ofDeviceId == null || portNumber == null) {
261 throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
262 }
263 macLearnerService.removeFromIgnoredPorts(DeviceId.deviceId(ofDeviceId),
264 PortNumber.portNumber(portNumber));
265 return Response.created(new URI("/remove/ignore-port/" +
266 ofDeviceId + PATH_DELIMITER +
267 portNumber)).status(OK).build();
268 } catch (URISyntaxException e) {
269 log.error("URISyntaxException occurred while removing ignore port deviceId: {} portNumber {}",
270 ofDeviceId, portNumber, e);
271 return Response.serverError().build();
272 }
273 }
274
275}