/* * Copyright 2016-present Open Networking Laboratory * * 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.onosproject.drivers.ovsdb; import org.onlab.packet.IpAddress; import org.onlab.packet.TpPort; import org.onosproject.net.AnnotationKeys; import org.onosproject.net.DeviceId; import org.onosproject.net.behaviour.BridgeName; import org.onosproject.net.behaviour.MirroringConfig; import org.onosproject.net.behaviour.MirroringDescription; import org.onosproject.net.behaviour.MirroringStatistics; import org.onosproject.net.behaviour.MirroringName; import org.onosproject.net.device.DeviceService; import org.onosproject.net.driver.AbstractHandlerBehaviour; import org.onosproject.net.driver.DriverHandler; import org.onosproject.ovsdb.controller.OvsdbBridge; import org.onosproject.ovsdb.controller.OvsdbClientService; import org.onosproject.ovsdb.controller.OvsdbConstant; import org.onosproject.ovsdb.controller.OvsdbController; import org.onosproject.ovsdb.controller.OvsdbMirror; import org.onosproject.ovsdb.controller.OvsdbNodeId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static org.onlab.util.Tools.delay; /** * Implementation of mirror config which allows to add, delete and get mirrorings statistics. */ public class OvsdbMirroringConfig extends AbstractHandlerBehaviour implements MirroringConfig { private static Logger log = LoggerFactory.getLogger(OvsdbMirroringConfig.class); /** * Adds a mirroring with a given description. * * @param bridge the bridge name * @param mirroringDescription mirroring description * @return true if succeeds, or false */ @Override public boolean addMirroring(BridgeName bridge, MirroringDescription mirroringDescription) { DriverHandler handler = handler(); OvsdbClientService ovsdbClient = getOvsdbClientService(handler); OvsdbMirror mirror = OvsdbMirror.builder(mirroringDescription).build(); return ovsdbClient.createMirror(bridge.name(), mirror); } /** * Removes a mirroring. * * @param mirroringName mirroring name */ @Override public void deleteMirroring(MirroringName mirroringName) { DriverHandler handler = handler(); OvsdbClientService ovsdbClient = getOvsdbClientService(handler); ovsdbClient.dropMirror(mirroringName); } /** * Returns a collection of MirroringStatistics. * * @return statistics collection */ @Override public Collection<MirroringStatistics> getMirroringStatistics() { DriverHandler handler = handler(); OvsdbClientService ovsdbClient = getOvsdbClientService(handler); return ovsdbClient.getMirroringStatistics(handler.data().deviceId()); } /** * Helper method which is used for getting OvsdbClientService. */ private OvsdbClientService getOvsdbClientService(DriverHandler handler) { OvsdbController ovsController = handler.get(OvsdbController.class); DeviceService deviceService = handler.get(DeviceService.class); DeviceId deviceId = handler.data().deviceId(); String[] splits = deviceId.toString().split(":"); if (splits == null || splits.length < 1) { log.warn("Wrong deviceId format"); return null; } /** * Each type of device has to be managed in a different way. */ switch (splits[0]) { case "ovsdb": OvsdbNodeId nodeId = changeDeviceIdToNodeId(deviceId); return ovsController.getOvsdbClient(nodeId); case "of": String[] mgmtAddress = deviceService.getDevice(deviceId) .annotations().value(AnnotationKeys.MANAGEMENT_ADDRESS).split(":"); String targetIp = mgmtAddress[0]; TpPort targetPort = null; if (mgmtAddress.length > 1) { targetPort = TpPort.tpPort(Integer.parseInt(mgmtAddress[1])); } List<OvsdbNodeId> nodeIds = ovsController.getNodeIds().stream() .filter(nodeID -> nodeID.getIpAddress().equals(targetIp)) .collect(Collectors.toList()); if (nodeIds.isEmpty()) { //TODO decide what port? ovsController.connect(IpAddress.valueOf(targetIp), targetPort == null ? TpPort.tpPort(OvsdbConstant.OVSDBPORT) : targetPort); delay(1000); //FIXME... connect is async } List<OvsdbClientService> clientServices = ovsController.getNodeIds().stream() .filter(nodeID -> nodeID.getIpAddress().equals(targetIp)) .map(ovsController::getOvsdbClient) .filter(cs -> cs.getBridges().stream().anyMatch(b -> dpidMatches(b, deviceId))) .collect(Collectors.toList()); checkState(!clientServices.isEmpty(), "No clientServices found"); //FIXME add connection to management address if null --> done ? return !clientServices.isEmpty() ? clientServices.get(0) : null; default: log.warn("Unmanaged device type"); } return null; } private static boolean dpidMatches(OvsdbBridge bridge, DeviceId deviceId) { checkArgument(bridge.datapathId().isPresent()); String bridgeDpid = "of:" + bridge.datapathId().get(); String ofDpid = deviceId.toString(); return bridgeDpid.equals(ofDpid); } /** * OvsdbNodeId(IP) is used in the adaptor while DeviceId(ovsdb:IP) * is used in the core. So DeviceId need be changed to OvsdbNodeId. * * @param deviceId the device id in ovsdb:ip format * @return the ovsdb node id */ private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) { String[] splits = deviceId.toString().split(":"); if (splits == null || splits.length < 1) { return null; } IpAddress ipAddress = IpAddress.valueOf(splits[1]); return new OvsdbNodeId(ipAddress, 0); } }