blob: 1e2576665101314eee9cfddf4bab607177b8c0c7 [file] [log] [blame]
/*
* Copyright 2017-2023 Open Networking Foundation (ONF) and the ONF Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opencord.maclearner.app.rest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.rest.AbstractWebResource;
import org.opencord.maclearner.api.DefaultMacLearner;
import org.opencord.maclearner.api.MacDeleteResult;
import org.opencord.maclearner.api.MacLearnerKey;
import org.opencord.maclearner.api.MacLearnerService;
import org.slf4j.Logger;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static javax.ws.rs.core.Response.Status.OK;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Mac Learner web resource.
*/
@Path("maclearner")
public class MacLearnerWebResource extends AbstractWebResource {
MacLearnerCodec codec = new MacLearnerCodec();
private final MacLearnerService macLearnerService = get(MacLearnerService.class);
private final Logger log = getLogger(getClass());
private static final String INVALID_PATH_PARAMETERS = "Invalid path parameters";
private static final String PATH_DELIMITER = "/";
/**
* Get all MAC Mappings.
*
* @return list of MAC Mapping json object with deviceId, portNumber, vlanId, macAddress fields
*/
@GET
@Path("/mapping/all")
@Produces(MediaType.APPLICATION_JSON)
public Response getAllMappings() {
Map<MacLearnerKey, MacAddress> macMappings = macLearnerService.getAllMappings();
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = mapper.createObjectNode();
ArrayNode macArray = mapper.createArrayNode();
if (macMappings == null) {
root.set("data", macArray);
return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
} else {
macMappings.forEach((k, v) -> macArray.add(
codec.encode(new DefaultMacLearner(k.getDeviceId(),
k.getPortNumber(),
k.getVlanId(),
v), this)
));
}
root.set("data", macArray);
return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
}
/**
* Get MAC Mapping for request paramaters.
*
* @param ofDeviceId device id
* @param portNumber port number
* @param vlanId vlan id
* @return MAC Address json object with macAddress field
* 204 NO_CONTENT if it does not exist
*/
@GET
@Path("/mapping/{ofDeviceId}/{portNumber}/{vlanId}")
@Produces(MediaType.APPLICATION_JSON)
public Response getMacMapping(@PathParam("ofDeviceId") String ofDeviceId,
@PathParam("portNumber") Integer portNumber,
@PathParam("vlanId") Short vlanId) {
Optional<MacAddress> mac = macLearnerService.getMacMapping(DeviceId.deviceId(ofDeviceId),
PortNumber.portNumber(portNumber),
VlanId.vlanId(vlanId));
if (mac.isEmpty()) {
log.warn("MAC Address not found for: ofDeviceId:{} portNumber:{} vlanId:{}",
ofDeviceId, portNumber, vlanId);
return Response.status(NO_CONTENT).build();
}
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = mapper.createObjectNode();
root.set("data", codec.encodeMac(mac.get(), this));
return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).status(OK).build();
}
/**
* Delete MAC Mapping for request paramaters.
*
* @param ofDeviceId device id
* @param portNumber port number
* @param vlanId vlan id
* @return URI of request
*/
@DELETE
@Path("/mapping/{ofDeviceId}/{portNumber}/{vlanId}")
@Produces(MediaType.APPLICATION_JSON)
public Response deleteMacMapping(@PathParam("ofDeviceId") String ofDeviceId,
@PathParam("portNumber") Integer portNumber,
@PathParam("vlanId") Short vlanId) {
try {
if (ofDeviceId == null || portNumber == null || vlanId == null) {
throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
}
MacDeleteResult deleteResult = macLearnerService.deleteMacMapping(DeviceId.deviceId(ofDeviceId),
PortNumber.portNumber(portNumber),
VlanId.vlanId(vlanId));
if (deleteResult.equals(MacDeleteResult.UNSUCCESSFUL)) {
return Response.status(NO_CONTENT).build();
}
return Response
.created(new URI("/delete/mapping/" +
ofDeviceId + PATH_DELIMITER +
portNumber + PATH_DELIMITER +
vlanId))
.status(OK)
.build();
} catch (URISyntaxException e) {
log.error("URI Syntax Exception occurred while deleting MAC Mapping " +
"for deviceId: {} portNumber: {} vlanId: {}",
ofDeviceId, portNumber, vlanId, e);
return Response.serverError().build();
}
}
/**
* Delete MAC Mappings for specific port of a device.
*
* @param ofDeviceId device id
* @param portNumber port number
* @return URI of request
*/
@DELETE
@Path("/mappings/{ofDeviceId}/{portNumber}")
@Produces(MediaType.APPLICATION_JSON)
public Response deleteMacMappings(@PathParam("ofDeviceId") String ofDeviceId,
@PathParam("portNumber") Integer portNumber) {
try {
if (ofDeviceId == null || portNumber == null) {
throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
}
boolean deleteSuccess = macLearnerService.deleteMacMappings(DeviceId.deviceId(ofDeviceId),
PortNumber.portNumber(portNumber));
if (!deleteSuccess) {
return Response.status(NO_CONTENT).build();
}
return Response.created(new URI("/delete/mappings/" +
ofDeviceId + PATH_DELIMITER +
portNumber)).status(OK).build();
} catch (URISyntaxException e) {
log.error("URI Syntax Exception occurred while deleting MAC Mappings for deviceId: {} portNumber: {}",
ofDeviceId, portNumber, e);
return Response.serverError().build();
}
}
/**
* Get ignored ports for MAC Mapping.
*
* @return list of ignored port json object with deviceId and portNumber fields
*/
@GET
@Path("/ports/ignored")
@Produces(MediaType.APPLICATION_JSON)
public Response getIgnoredPorts() {
Map<DeviceId, Set<PortNumber>> ignoredPorts = macLearnerService.getIgnoredPorts();
ObjectMapper mapper = new ObjectMapper();
ObjectNode root = mapper.createObjectNode();
ArrayNode ignoredPortsArray = mapper.createArrayNode();
if (ignoredPorts == null) {
root.set("data", ignoredPortsArray);
return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
} else {
for (Map.Entry<DeviceId, Set<PortNumber>> entry : ignoredPorts.entrySet()) {
entry.getValue().forEach(portNumber -> ignoredPortsArray.add(
codec.encodePort(new MacLearnerKey(entry.getKey(), portNumber, VlanId.NONE), this)
));
}
}
root.set("data", ignoredPortsArray);
return Response.ok(root, MediaType.APPLICATION_JSON_TYPE).build();
}
/**
* Add to ignore ports map.
*
* @param ofDeviceId deviceId
* @param portNumber portNumber
* @return URI of request
*/
@POST
@Path("/ignore-port/{ofDeviceId}/{portNumber}")
@Produces(MediaType.APPLICATION_JSON)
public Response addPortToIgnore(@PathParam("ofDeviceId") String ofDeviceId,
@PathParam("portNumber") Integer portNumber) {
try {
if (ofDeviceId == null || portNumber == null) {
throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
}
macLearnerService.addPortToIgnore(DeviceId.deviceId(ofDeviceId),
PortNumber.portNumber(portNumber));
return Response.created(new URI("/add/ignore-port/" +
ofDeviceId + PATH_DELIMITER +
portNumber)).status(OK).build();
} catch (URISyntaxException e) {
log.error("URI Syntax Exception occurred while adding ignore port deviceId: {} portNumber {}",
ofDeviceId, portNumber, e);
return Response.serverError().build();
}
}
/**
* Remove from ignored ports map.
*
* @param ofDeviceId device id
* @param portNumber port number
* @return URI of request
*/
@DELETE
@Path("/ignore-port/{ofDeviceId}/{portNumber}")
@Produces(MediaType.APPLICATION_JSON)
public Response removeFromIgnoredPorts(@PathParam("ofDeviceId") String ofDeviceId,
@PathParam("portNumber") Integer portNumber) {
try {
if (ofDeviceId == null || portNumber == null) {
throw new IllegalArgumentException(INVALID_PATH_PARAMETERS);
}
macLearnerService.removeFromIgnoredPorts(DeviceId.deviceId(ofDeviceId),
PortNumber.portNumber(portNumber));
return Response.created(new URI("/remove/ignore-port/" +
ofDeviceId + PATH_DELIMITER +
portNumber)).status(OK).build();
} catch (URISyntaxException e) {
log.error("URISyntaxException occurred while removing ignore port deviceId: {} portNumber {}",
ofDeviceId, portNumber, e);
return Response.serverError().build();
}
}
}