Pier Ventre
Committed by Gerrit Code Review

[ONOS-5070] Adds mirroring functionality.

Changes:
- Adds mirroring behaviour;
- Adds mirroring description;
- Adds mirroring name;
- Implements for Ovsdb the mirroring;
- Adds OvsdbMirror entity;
- Adds constants related to Mirror table;
- Fix one issue related to Mirror table
- Extends OvsdbClientService introducing mirroring;
- Implements mirroring functionality in DefaulOvsdbClient;
- Support for different types of device id

Change-Id: Ie291f49b3c61b7998010f555ae11deb8c021063d
/*
* 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.net.behaviour;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import org.onlab.packet.VlanId;
import org.onosproject.net.AbstractDescription;
import org.onosproject.net.SparseAnnotations;
import java.util.List;
import java.util.Optional;
/**
* Default implementation of mirroring description entity.
*/
@Beta
public class DefaultMirroringDescription extends AbstractDescription
implements MirroringDescription {
private final MirroringName mirroringName;
private final List<String> monitorSrcPorts;
private final List<String> monitorDstPorts;
private final List<VlanId> monitorVlans;
private final Optional<String> mirrorPort;
private final Optional<VlanId> mirrorVlan;
/**
* Creates a mirroring description using the supplied information.
*
* @param name the name of the mirroring
* @param monitorsrcports the monitored src ports
* @param monitordstports the monitored dst ports
* @param monitorvlans the monitored vlans
* @param mirrorport the mirror port
* @param mirrorvlan the mirror vlan
* @param annotations optional key/value annotations
*/
public DefaultMirroringDescription(MirroringName name,
List<String> monitorsrcports,
List<String> monitordstports,
List<VlanId> monitorvlans,
Optional<String> mirrorport,
Optional<VlanId> mirrorvlan,
SparseAnnotations... annotations) {
super(annotations);
this.mirroringName = name;
this.monitorSrcPorts = monitorsrcports;
this.monitorDstPorts = monitordstports;
this.monitorVlans = monitorvlans;
this.mirrorPort = mirrorport;
this.mirrorVlan = mirrorvlan;
}
/**
* Returns mirroring name.
*
* @return mirroring name
*/
@Override
public MirroringName name() {
return mirroringName;
}
/**
* Returns src ports to monitor.
* If it is empty, then no src port has
* to be monitored.
*
* @return set of src ports to monitor
*/
@Override
public List<String> monitorSrcPorts() {
return monitorSrcPorts;
}
/**
* Returns dst ports to monitor.
* If it is empty, then no dst port has
* to be monitored.
*
* @return set of dst ports to monitor
*/
@Override
public List<String> monitorDstPorts() {
return monitorDstPorts;
}
/**
* Returns vlans to monitor.
* If it is empty, then no vlan has
* to be monitored.
*
* @return monitored vlan
*/
@Override
public List<VlanId> monitorVlans() {
return monitorVlans;
}
/**
* Returns mirror port.
* If it is not set, then no destination
* port for mirrored packets.
*
* @return mirror port
*/
@Override
public Optional<String> mirrorPort() {
return mirrorPort;
}
/**
* Returns mirror vlan.
* If it is not set the no destination
* vlan for mirrored packets.
*
* @return mirror vlan
*/
@Override
public Optional<VlanId> mirrorVlan() {
return mirrorVlan;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("name", name())
.add("monitorsrcports", monitorSrcPorts())
.add("monitordstports", monitorDstPorts())
.add("monitorvlans", monitorVlans())
.add("mirrorport", mirrorPort())
.add("mirrorvlan", mirrorVlan())
.toString();
}
}
/*
* 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.net.behaviour;
import com.google.common.annotations.Beta;
import org.onosproject.net.driver.HandlerBehaviour;
import java.util.Collection;
/**
* Behaviour for handling various drivers for mirroring configurations.
*/
@Beta
public interface MirroringConfig extends HandlerBehaviour {
/**
* Adds a mirroring with a given description.
*
* @param bridge the bridge name
* @param mirroringDescription mirroring description
* @return true if succeeds, or false
*/
boolean addMirroring(BridgeName bridge, MirroringDescription mirroringDescription);
/**
* Removes a mirroring.
*
* @param mirroringName mirroring name
*/
void deleteMirroring(MirroringName mirroringName);
/**
* Returns a collection of MirroringStatistics.
*
* @return statistics collection
*/
Collection<MirroringStatistics> getMirroringStatistics();
}
/*
* 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.net.behaviour;
import com.google.common.annotations.Beta;
import org.onlab.packet.VlanId;
import org.onosproject.net.Annotated;
import org.onosproject.net.Description;
import java.util.List;
import java.util.Optional;
/**
* The abstraction of a mirroring. Port mirroring is a method of monitoring
* network traffic that forwards a copy of each incoming or outgoing packet from
* one port (Monitor port) on a network switch to another port (Mirror port)
* where the packet can be analyzed.
*/
@Beta
public interface MirroringDescription extends Description, Annotated {
/**
* Returns mirroring name.
*
* @return mirroring name
*/
MirroringName name();
/**
* Returns src ports to monitor.
* If it is empty, then no src port has
* to be monitored.
*
* @return set of src ports to monitor
*/
List<String> monitorSrcPorts();
/**
* Returns dst ports to monitor.
* If it is empty, then no dst port has
* to be monitored.
*
* @return set of dst ports to monitor
*/
List<String> monitorDstPorts();
/**
* Returns vlans to monitor.
* If it is empty, then no vlan has
* to be monitored.
*
* @return monitored vlan
*/
List<VlanId> monitorVlans();
/**
* Returns mirror port.
* If it is not set, then no destination
* port for mirrored packets.
*
* @return mirror port
*/
Optional<String> mirrorPort();
/**
* Returns mirror vlan.
* If it is not set then no destination
* vlan for mirrored packets.
*
* @return mirror vlan
*/
Optional<VlanId> mirrorVlan();
}
/*
* 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.net.behaviour;
import com.google.common.base.MoreObjects;
import java.util.Objects;
/**
* Represents for a mirroring name.
*/
public final class MirroringName {
private final String name;
private MirroringName(String name) {
this.name = name;
}
/**
* Creates a mirroring name using the supplied string.
*
* @param name mirroring name
* @return a port mirroring name
*/
public static MirroringName mirroringName(String name) {
return new MirroringName(name);
}
/**
* Returns the mirroring name string.
*
* @return name string
*/
public String name() {
return name;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MirroringName) {
final MirroringName that = (MirroringName) obj;
return this.getClass() == that.getClass() &&
Objects.equals(this.name, that.name);
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("name", name)
.toString();
}
}
/*
* 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.net.behaviour;
import com.google.common.base.MoreObjects;
import java.util.Map;
import java.util.Objects;
/**
* Represents statistics associated to a mirroring.
*/
public final class MirroringStatistics {
private MirroringName mirroringName;
private int txBytes;
private int txPackets;
/**
* Statistics associated to a named mirroring.
*
* @param name the name of the mirroring
* @param bytes transmitted bytes
* @param packets transmitted packets
*/
private MirroringStatistics(String name, int bytes, int packets) {
this.mirroringName = MirroringName.mirroringName(name);
this.txBytes = bytes;
this.txPackets = packets;
}
/**
*
* Creates a MirroringStatistics using the supplied information.
*
* @param name the name of the mirroring
* @param statistics the associated statistics
* @return the MirroringStatistics object
*/
public static MirroringStatistics mirroringStatistics(String name, Map<String, Integer> statistics) {
return new MirroringStatistics(name, statistics.get("tx_bytes"), statistics.get("tx_packets"));
}
/**
* Returns the mirroring name string.
*
* @return name string
*/
public MirroringName name() {
return mirroringName;
}
/**
* Returns the transmitted bytes.
*
* @return the bytes
*/
public long bytes() {
return txBytes;
}
/**
* Returns the transmitted packtes.
*
* @return the packets
*/
public long packtes() {
return txPackets;
}
@Override
public int hashCode() {
return Objects.hash(name().name(), txBytes, txPackets);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MirroringStatistics) {
final MirroringStatistics that = (MirroringStatistics) obj;
return this.getClass() == that.getClass() &&
Objects.equals(this.mirroringName, that.mirroringName) &&
Objects.equals(this.txBytes, that.txBytes) &&
Objects.equals(this.txPackets, that.txPackets);
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("name", name())
.add("tx_bytes", bytes())
.add("tx_packets", packtes())
.toString();
}
}
......@@ -28,6 +28,7 @@ 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.OvsdbNodeId;
......@@ -83,7 +84,7 @@ public class OvsdbControllerConfig extends AbstractHandlerBehaviour implements C
if (nodeIds.size() == 0) {
//TODO decide what port?
ovsController.connect(IpAddress.valueOf(targetIp),
targetPort == null ? TpPort.tpPort(6640) : targetPort);
targetPort == null ? TpPort.tpPort(OvsdbConstant.OVSDBPORT) : targetPort);
delay(1000); //FIXME... connect is async
}
List<OvsdbClientService> clientServices = ovsController.getNodeIds().stream()
......
/*
* 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.size() == 0) {
//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.size() > 0, "No clientServices found");
//FIXME add connection to management address if null --> done ?
return clientServices.size() > 0 ? 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);
}
}
......@@ -28,6 +28,8 @@
manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*">
<behaviour api="org.onosproject.net.behaviour.ControllerConfig"
impl="org.onosproject.drivers.ovsdb.OvsdbControllerConfig"/>
<behaviour api="org.onosproject.net.behaviour.MirroringConfig"
impl="org.onosproject.drivers.ovsdb.OvsdbMirroringConfig"/>
</driver>
</drivers>
......
......@@ -19,6 +19,8 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.behaviour.MirroringStatistics;
import org.onosproject.net.behaviour.MirroringName;
import org.onosproject.ovsdb.rfc.jsonrpc.OvsdbRpc;
import org.onosproject.ovsdb.rfc.message.TableUpdates;
import org.onosproject.ovsdb.rfc.notation.Row;
......@@ -40,6 +42,41 @@ public interface OvsdbClientService extends OvsdbRpc {
OvsdbNodeId nodeId();
/**
* Creates a mirror port. Mirrors the traffic
* that goes to selectDstPort or comes from
* selectSrcPort or packets containing selectVlan
* to mirrorPort or to all ports that trunk mirrorVlan.
*
* @param bridgeName the name of the bridge
* @param mirror the OVSDB mirror description
* @return true if mirror creation is successful, false otherwise
*/
boolean createMirror(String bridgeName, OvsdbMirror mirror);
/**
* Gets the Mirror uuid.
*
* @param mirrorName mirror name
* @return mirror uuid, empty if no uuid is found
*/
String getMirrorUuid(String mirrorName);
/**
* Gets mirroring statistics of the device.
*
* @param deviceId target device id
* @return set of mirroring statistics; empty if no mirror is found
*/
Set<MirroringStatistics> getMirroringStatistics(DeviceId deviceId);
/**
* Drops the configuration for mirror.
*
* @param mirroringName
*/
void dropMirror(MirroringName mirroringName);
/**
* Creates a tunnel port with given options.
*
* @deprecated version 1.7.0 - Hummingbird
......
......@@ -41,6 +41,7 @@ public final class OvsdbConstant {
/** Bridge table. */
public static final String BRIDGE = "Bridge";
public static final String PORTS = "ports";
public static final String MIRRORS = "mirrors";
// other configs
public static final String DATAPATH_ID = "datapath-id";
public static final String DISABLE_INBAND = "disable-in-band";
......@@ -66,6 +67,9 @@ public final class OvsdbConstant {
/** Controller table. */
public static final String CONTROLLER = "Controller";
/** Mirror table. */
public static final String MIRROR = "Mirror";
/** Ovsdb bridge name. */
// TODO remove this particular bridge name from OVSDB provider
public static final String INTEGRATION_BRIDGE = "br-int";
......
/*
* 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.ovsdb.controller;
import com.google.common.collect.Maps;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.behaviour.MirroringDescription;
import org.onosproject.ovsdb.rfc.notation.Uuid;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* The class representing an OVSDB mirror.
* This class is immutable.
*/
public final class OvsdbMirror {
private final String mirroringName;
private boolean selectAll;
private final Set<Uuid> monitorSrcPorts;
private final Set<Uuid> monitorDstPorts;
private final Set<Short> monitorVlans;
private final Optional<Uuid> mirrorPort;
private final Optional<Short> mirrorVlan;
private Map<String, String> externalIds;
/**
* Creates an OvsdbMirror using the given inputs.
*
* @param mirroringName the name of the mirroring
* @param selectAll mirrors all ports
* @param monitorSrcPorts the monitored src ports
* @param monitorDstPorts the monitored dst ports
* @param monitorVlans the monitored vlans
* @param mirrorPort the mirror port
* @param mirrorVlan the mirror vlan
* @param externalIds optional key/value options
*/
private OvsdbMirror(String mirroringName, boolean selectAll, Set<Uuid> monitorSrcPorts, Set<Uuid> monitorDstPorts,
Set<Short> monitorVlans, Optional<Uuid> mirrorPort, Optional<Short> mirrorVlan,
Map<String, String> externalIds) {
this.mirroringName = mirroringName;
this.selectAll = selectAll;
this.monitorSrcPorts = monitorSrcPorts;
this.monitorDstPorts = monitorDstPorts;
this.monitorVlans = monitorVlans;
this.mirrorPort = mirrorPort;
this.mirrorVlan = mirrorVlan;
this.externalIds = externalIds;
}
/**
* Returns the name of the mirroring.
*
* @return the string representing the name
*/
public String mirroringName() {
return mirroringName;
}
/**
* Returns selectAll value.
*
* @return mirrors all ports if true
*/
public boolean selectAll() {
return selectAll;
}
/**
* Returns the monitored src ports.
*
* @return the uuids set of the ports
*/
public Set<Uuid> monitorSrcPorts() {
return monitorSrcPorts;
}
/**
* Returns the monitored dst ports.
*
* @return the uuids set of the ports
*/
public Set<Uuid> monitorDstPorts() {
return monitorDstPorts;
}
/**
* Returns the monitored vlans.
*
* @return the vlans set
*/
public Set<Short> monitorVlans() {
return monitorVlans;
}
/**
* Returns the mirror port.
*
* @return the uuid port if present, otherwise null
*/
public Uuid mirrorPort() {
return mirrorPort.orElse(null);
}
/**
* Returns the mirror vlan.
*
* @return the vlan id if present, otherwise null
*/
public Short mirrorVlan() {
return mirrorVlan.orElse(null);
}
/**
* Returns the optional external ids.
*
* @return the external ids.
*/
public Map<String, String> externalIds() {
return externalIds;
}
@Override
public int hashCode() {
return Objects.hash(mirroringName, selectAll, monitorSrcPorts, monitorDstPorts,
monitorVlans, mirrorPort, mirrorVlan, externalIds);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof OvsdbMirror) {
final OvsdbMirror other = (OvsdbMirror) obj;
return Objects.equals(this.mirroringName, other.mirroringName) &&
Objects.equals(this.selectAll, other.selectAll) &&
Objects.equals(this.monitorSrcPorts, other.monitorSrcPorts) &&
Objects.equals(this.monitorDstPorts, other.monitorDstPorts) &&
Objects.equals(this.monitorVlans, other.monitorVlans) &&
Objects.equals(this.mirrorPort, other.mirrorPort) &&
Objects.equals(this.mirrorVlan, other.mirrorVlan) &&
Objects.equals(this.externalIds, other.externalIds);
}
return false;
}
@Override
public String toString() {
return toStringHelper(this)
.add("mirroringName", mirroringName())
.add("selectAll", selectAll())
.add("monitorSrcPorts", monitorSrcPorts())
.add("monitorDstPorts", monitorDstPorts())
.add("monitorVlans", monitorVlans())
.add("mirrorPort", mirrorPort())
.add("mirrorVlan", mirrorVlan())
.add("externalIds", externalIds())
.toString();
}
/**
* Returns new OVSDB mirror builder.
*
* @return ovsdb mirror builder
*/
public static OvsdbMirror.Builder builder() {
return new OvsdbMirror.Builder();
}
/**
* Returns new OVSDB mirror builder with mirror description.
*
* @param mirrorDesc mirror description
* @return ovsdb mirror builder
*/
public static OvsdbMirror.Builder builder(MirroringDescription mirrorDesc) {
return new OvsdbMirror.Builder(mirrorDesc);
}
/**
* Builder of OVSDB mirror entities.
*/
public static final class Builder {
private String mirroringName;
private boolean selectAll;
private Set<Uuid> monitorSrcPorts;
private Set<Uuid> monitorDstPorts;
private Set<Short> monitorVlans;
private Optional<Uuid> mirrorPort;
private Optional<Short> mirrorVlan;
private Map<String, String> externalIds = Maps.newHashMap();
/**
* Constructs an empty builder.
*/
private Builder() {
}
/**
* Constructs a builder with a given mirror description.
*
* @param mirrorDesc mirror description
*/
private Builder(MirroringDescription mirrorDesc) {
mirroringName = mirrorDesc.name().name();
selectAll = false;
monitorSrcPorts = mirrorDesc.monitorSrcPorts().parallelStream()
.map(monitorSrcPort -> Uuid.uuid(monitorSrcPort))
.collect(Collectors.toSet());
monitorDstPorts = mirrorDesc.monitorDstPorts().parallelStream()
.map(monitorDstPort -> Uuid.uuid(monitorDstPort))
.collect(Collectors.toSet());
monitorVlans = mirrorDesc.monitorVlans().parallelStream()
.map(monitorVlan -> monitorVlan.toShort())
.collect(Collectors.toSet());
if (mirrorDesc.mirrorPort().isPresent()) {
mirrorPort = Optional.of(Uuid.uuid(mirrorDesc.mirrorPort().get()));
} else {
mirrorPort = Optional.empty();
}
if (mirrorDesc.mirrorVlan().isPresent()) {
mirrorVlan = Optional.of(mirrorDesc.mirrorVlan().get().toShort());
} else {
mirrorVlan = Optional.empty();
}
externalIds.putAll(((DefaultAnnotations) mirrorDesc.annotations()).asMap());
}
/**
* Returns new OVSDB mirror.
*
* @return ovsdb mirror
*/
public OvsdbMirror build() {
return new OvsdbMirror(mirroringName, selectAll, monitorSrcPorts, monitorDstPorts, monitorVlans,
mirrorPort, mirrorVlan, externalIds);
}
/**
* Returns OVSDB mirror builder with a given name.
*
* @param name name of the mirror
* @return ovsdb interface builder
*/
public OvsdbMirror.Builder mirroringName(String name) {
this.mirroringName = name;
return this;
}
/**
* Returns OVSDB mirror builder with select all.
*
* @param all mirrors all ports
* @return ovsdb interface builder
*/
public OvsdbMirror.Builder selectAll(boolean all) {
this.selectAll = all;
return this;
}
/**
* Returns OVSDB mirror builder with a given set
* of monitored src ports.
*
* @param monitorPorts ports to be monitored
* @return ovsdb mirror builder
*/
public OvsdbMirror.Builder monitorSrcPorts(Set<Uuid> monitorPorts) {
this.monitorSrcPorts = monitorPorts;
return this;
}
/**
* Returns OVSDB mirror builder with a given set
* of monitored dst ports.
*
* @param monitorPorts ports to be monitored
* @return ovsdb mirror builder
*/
public OvsdbMirror.Builder monitorDstPorts(Set<Uuid> monitorPorts) {
this.monitorDstPorts = monitorPorts;
return this;
}
/**
* Returns OVSDB mirror builder with a given set
* of monitored vlans.
*
* @param vlans vlans to be monitored
* @return ovsdb mirror builder
*/
public OvsdbMirror.Builder monitorVlans(Set<Short> vlans) {
this.monitorVlans = vlans;
return this;
}
/**
* Returns OVSDB mirror builder with a given mirror port.
*
* @param port the mirror port
* @return ovsdb mirror builder
*/
public OvsdbMirror.Builder mirrorPort(Uuid port) {
this.mirrorPort = Optional.ofNullable(port);
return this;
}
/**
* Returns OVSDB mirror builder with a given mirror vlan.
*
* @param vlan the mirror vlan
* @return ovsdb mirror builder
*/
public OvsdbMirror.Builder mirrorVlan(Short vlan) {
this.mirrorVlan = Optional.ofNullable(vlan);
return this;
}
/**
* Returns OVSDB mirror builder with given external ids.
*
* @param ids the external ids
* @return ovsdb mirror builder
*/
public OvsdbMirror.Builder externalIds(Map<String, String> ids) {
this.externalIds = ids;
return this;
}
}
}
......@@ -17,6 +17,8 @@ package org.onosproject.ovsdb.controller.driver;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
......@@ -30,10 +32,13 @@ import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.BridgeDescription;
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.behaviour.MirroringStatistics;
import org.onosproject.net.behaviour.MirroringName;
import org.onosproject.ovsdb.controller.OvsdbBridge;
import org.onosproject.ovsdb.controller.OvsdbClientService;
import org.onosproject.ovsdb.controller.OvsdbInterface;
import org.onosproject.ovsdb.controller.OvsdbInterface.Type;
import org.onosproject.ovsdb.controller.OvsdbMirror;
import org.onosproject.ovsdb.controller.OvsdbNodeId;
import org.onosproject.ovsdb.controller.OvsdbPort;
import org.onosproject.ovsdb.controller.OvsdbPortName;
......@@ -41,6 +46,7 @@ import org.onosproject.ovsdb.controller.OvsdbPortNumber;
import org.onosproject.ovsdb.controller.OvsdbRowStore;
import org.onosproject.ovsdb.controller.OvsdbStore;
import org.onosproject.ovsdb.controller.OvsdbTableStore;
import org.onosproject.ovsdb.rfc.jsonrpc.Callback;
import org.onosproject.ovsdb.rfc.message.OperationResult;
import org.onosproject.ovsdb.rfc.message.TableUpdates;
......@@ -61,6 +67,7 @@ import org.onosproject.ovsdb.rfc.schema.TableSchema;
import org.onosproject.ovsdb.rfc.table.Bridge;
import org.onosproject.ovsdb.rfc.table.Controller;
import org.onosproject.ovsdb.rfc.table.Interface;
import org.onosproject.ovsdb.rfc.table.Mirror;
import org.onosproject.ovsdb.rfc.table.OvsdbTable;
import org.onosproject.ovsdb.rfc.table.Port;
import org.onosproject.ovsdb.rfc.table.TableGenerator;
......@@ -73,10 +80,12 @@ import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
......@@ -104,6 +113,7 @@ public class DefaultOvsdbClient implements OvsdbProviderService, OvsdbClientServ
private final Map<String, SettableFuture<? extends Object>> requestResult = Maps.newHashMap();
private final Map<String, DatabaseSchema> schema = Maps.newHashMap();
/**
* Creates an OvsdbClient.
*
......@@ -234,6 +244,107 @@ public class DefaultOvsdbClient implements OvsdbProviderService, OvsdbClientServ
ovsdbStore.createOrUpdateOvsdbStore(dbName, tableStore);
}
/**
* Gets the Mirror uuid.
*
* @param mirrorName mirror name
* @return mirror uuid, empty if no uuid is found
*/
@Override
public String getMirrorUuid(String mirrorName) {
DatabaseSchema dbSchema = schema.get(DATABASENAME);
OvsdbRowStore rowStore = getRowStore(DATABASENAME, MIRROR);
if (rowStore == null) {
log.warn("The mirror uuid is null");
return null;
}
ConcurrentMap<String, Row> mirrorTableRows = rowStore.getRowStore();
if (mirrorTableRows == null) {
log.warn("The mirror uuid is null");
return null;
}
for (String uuid : mirrorTableRows.keySet()) {
Mirror mirror = (Mirror) TableGenerator
.getTable(dbSchema, mirrorTableRows.get(uuid), OvsdbTable.MIRROR);
String name = mirror.getName();
if (name.contains(mirrorName)) {
return uuid;
}
}
log.warn("Mirroring not found");
return null;
}
/**
* Gets mirrors of the device.
*
* @param deviceId target device id
* @return set of mirroring; empty if no mirror is found
*/
@Override
public Set<MirroringStatistics> getMirroringStatistics(DeviceId deviceId) {
Uuid bridgeUuid = getBridgeUuid(deviceId);
if (bridgeUuid == null) {
log.warn("Couldn't find bridge {} in {}", deviceId, nodeId.getIpAddress());
return null;
}
List<MirroringStatistics> mirrorings = getMirrorings(bridgeUuid);
if (mirrorings == null) {
log.warn("Couldn't find mirrors in {}", nodeId.getIpAddress());
return null;
}
return ImmutableSet.copyOf(mirrorings);
}
/**
* Helper method which retrieves mirrorings statistics using bridge uuid.
*
* @param bridgeUuid the uuid of the bridge
* @return the list of the mirrorings statistics.
*/
private List<MirroringStatistics> getMirrorings(Uuid bridgeUuid) {
DatabaseSchema dbSchema = schema.get(DATABASENAME);
if (dbSchema == null) {
log.warn("Unable to retrieve dbSchema {}", DATABASENAME);
return null;
}
OvsdbRowStore rowStore = getRowStore(DATABASENAME, BRIDGE);
if (rowStore == null) {
log.warn("Unable to retrieve rowStore {} of {}", BRIDGE, DATABASENAME);
return null;
}
Row bridgeRow = rowStore.getRow(bridgeUuid.value());
Bridge bridge = (Bridge) TableGenerator.
getTable(dbSchema, bridgeRow, OvsdbTable.BRIDGE);
Set<Uuid> mirroringsUuids = (Set<Uuid>) ((OvsdbSet) bridge
.getMirrorsColumn().data()).set();
OvsdbRowStore mirrorRowStore = getRowStore(DATABASENAME, MIRROR);
if (mirrorRowStore == null) {
log.warn("Unable to retrieve rowStore {} of {}", MIRROR, DATABASENAME);
return null;
}
List<MirroringStatistics> mirroringStatistics = new ArrayList<>();
ConcurrentMap<String, Row> mirrorTableRows = mirrorRowStore.getRowStore();
mirrorTableRows.forEach((key, row) -> {
if (!mirroringsUuids.contains(Uuid.uuid(key))) {
return;
}
Mirror mirror = (Mirror) TableGenerator
.getTable(dbSchema, row, OvsdbTable.MIRROR);
mirroringStatistics.add(MirroringStatistics.mirroringStatistics(mirror.getName(),
(Map<String, Integer>) ((OvsdbMap) mirror
.getStatisticsColumn().data()).map()));
});
return ImmutableList.copyOf(mirroringStatistics);
}
@Override
public String getPortUuid(String portName, String bridgeUuid) {
DatabaseSchema dbSchema = schema.get(DATABASENAME);
......@@ -502,6 +613,142 @@ public class DefaultOvsdbClient implements OvsdbProviderService, OvsdbClientServ
deleteConfig(BRIDGE, UUID, bridgeUuid, DATABASENAME, BRIDGES);
}
/**
* Creates a mirror port. Mirrors the traffic
* that goes to selectDstPort or comes from
* selectSrcPort or packets containing selectVlan
* to mirrorPort or to all ports that trunk mirrorVlan.
*
* @param mirror the OVSDB mirror description
* @return true if mirror creation is successful, false otherwise
*/
@Override
public boolean createMirror(String bridgeName, OvsdbMirror mirror) {
/**
* Retrieves bridge's uuid. It is necessary to update
* Bridge table.
*/
String bridgeUuid = getBridgeUuid(bridgeName);
if (bridgeUuid == null) {
log.warn("Couldn't find bridge {} in {}", bridgeName, nodeId.getIpAddress());
return false;
}
OvsdbMirror.Builder mirrorBuilder = OvsdbMirror.builder();
mirrorBuilder.mirroringName(mirror.mirroringName());
mirrorBuilder.selectAll(mirror.selectAll());
/**
* Retrieves the uuid of the monitored dst ports.
*/
mirrorBuilder.monitorDstPorts(mirror.monitorDstPorts().parallelStream()
.map(dstPort -> {
String dstPortUuid = getPortUuid(dstPort.value(), bridgeUuid);
if (dstPortUuid != null) {
return Uuid.uuid(dstPortUuid);
}
log.warn("Couldn't find port {} in {}",
dstPort.value(), nodeId.getIpAddress());
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toSet())
);
/**
* Retrieves the uuid of the monitored src ports.
*/
mirrorBuilder.monitorSrcPorts(mirror.monitorSrcPorts().parallelStream()
.map(srcPort -> {
String srcPortUuid = getPortUuid(srcPort.value(), bridgeUuid);
if (srcPortUuid != null) {
return Uuid.uuid(srcPortUuid);
}
log.warn("Couldn't find port {} in {}",
srcPort.value(), nodeId.getIpAddress());
return null;
}).filter(Objects::nonNull)
.collect(Collectors.toSet())
);
mirrorBuilder.monitorVlans(mirror.monitorVlans());
mirrorBuilder.mirrorPort(mirror.mirrorPort());
mirrorBuilder.mirrorVlan(mirror.mirrorVlan());
mirrorBuilder.externalIds(mirror.externalIds());
mirror = mirrorBuilder.build();
if (mirror.monitorDstPorts().size() == 0 &&
mirror.monitorSrcPorts().size() == 0 &&
mirror.monitorVlans().size() == 0) {
log.warn("Invalid monitoring data");
return false;
}
DatabaseSchema dbSchema = schema.get(DATABASENAME);
Mirror mirrorEntry = (Mirror) TableGenerator.createTable(dbSchema, OvsdbTable.MIRROR);
mirrorEntry.setName(mirror.mirroringName());
mirrorEntry.setSelectDstPort(mirror.monitorDstPorts());
mirrorEntry.setSelectSrcPort(mirror.monitorSrcPorts());
mirrorEntry.setSelectVlan(mirror.monitorVlans());
mirrorEntry.setExternalIds(mirror.externalIds());
/**
* If mirror port, retrieves the uuid of the mirror port.
*/
if (mirror.mirrorPort() != null) {
String outputPortUuid = getPortUuid(mirror.mirrorPort().value(), bridgeUuid);
if (outputPortUuid == null) {
log.warn("Couldn't find port {} in {}", mirror.mirrorPort().value(), nodeId.getIpAddress());
return false;
}
mirrorEntry.setOutputPort(Uuid.uuid(outputPortUuid));
} else if (mirror.mirrorVlan() != null) {
mirrorEntry.setOutputVlan(mirror.mirrorVlan());
} else {
log.warn("Invalid mirror, no mirror port and no mirror vlan");
return false;
}
ArrayList<Operation> operations = Lists.newArrayList();
Insert mirrorInsert = new Insert(dbSchema.getTableSchema("Mirror"), "Mirror", mirrorEntry.getRow());
operations.add(mirrorInsert);
// update the bridge table
Condition condition = ConditionUtil.isEqual(UUID, Uuid.uuid(bridgeUuid));
Mutation mutation = MutationUtil.insert(MIRRORS, Uuid.uuid("Mirror"));
List<Condition> conditions = Lists.newArrayList(condition);
List<Mutation> mutations = Lists.newArrayList(mutation);
operations.add(new Mutate(dbSchema.getTableSchema("Bridge"), conditions, mutations));
transactConfig(DATABASENAME, operations);
log.info("Created mirror {}", mirror.mirroringName());
return true;
}
/**
* Drops the configuration for mirror.
*
* @param mirroringName
*/
@Override
public void dropMirror(MirroringName mirroringName) {
String mirrorUuid = getMirrorUuid(mirroringName.name());
if (mirrorUuid != null) {
log.info("Deleted mirror {}", mirroringName.name());
deleteConfig(MIRROR, UUID, mirrorUuid, BRIDGE, MIRRORS);
}
log.warn("Unable to delete {}", mirroringName.name());
return;
}
@Deprecated
@Override
public boolean createTunnel(String bridgeName, String ifaceName, String tunnelType,
......
......@@ -22,9 +22,12 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.behaviour.MirroringStatistics;
import org.onosproject.net.behaviour.MirroringName;
import org.onosproject.ovsdb.controller.OvsdbBridge;
import org.onosproject.ovsdb.controller.OvsdbClientService;
import org.onosproject.ovsdb.controller.OvsdbInterface;
import org.onosproject.ovsdb.controller.OvsdbMirror;
import org.onosproject.ovsdb.controller.OvsdbNodeId;
import org.onosproject.ovsdb.controller.OvsdbPort;
import org.onosproject.ovsdb.rfc.message.TableUpdates;
......@@ -46,6 +49,54 @@ public class OvsdbClientServiceAdapter implements OvsdbClientService {
return null;
}
/**
* Creates a mirror port. Mirrors the traffic
* that goes to selectDstPort or comes from
* selectSrcPort or packets containing selectVlan
* to mirrorPort or to all ports that trunk mirrorVlan.
*
* @param bridgeName the name of the bridge
* @param mirror the OVSDB mirror description
* @return true if mirror creation is successful, false otherwise
*/
@Override
public boolean createMirror(String bridgeName, OvsdbMirror mirror) {
return true;
}
/**
* Gets the Mirror uuid.
*
* @param mirrorName mirror name
* @return mirror uuid, empty if no uuid is found
*/
@Override
public String getMirrorUuid(String mirrorName) {
return null;
}
/**
* Gets mirroring statistics of the device.
*
* @param deviceId target device id
* @return set of mirroring statistics; empty if no mirror is found
*/
@Override
public Set<MirroringStatistics> getMirroringStatistics(DeviceId deviceId) {
return null;
}
/**
* Drops the configuration for mirror.
*
* @param mirroringName
*/
@Override
public void dropMirror(MirroringName mirroringName) {
}
@Override
public boolean createTunnel(String bridgeName, String portName, String tunnelType, Map<String, String> options) {
return true;
......
......@@ -203,7 +203,7 @@ public class Mirror extends AbstractOvsdbTableService {
* of attributes.
* @param outputVlan the column data which column name is "output_vlan"
*/
public void setOutputVlan(Set<Short> outputVlan) {
public void setOutputVlan(Short outputVlan) {
ColumnDescription columndesc = new ColumnDescription(MirrorColumn.OUTPUTVLAN.columnName(),
"setOutputVlan", VersionNum.VERSION100);
super.setDataHandler(columndesc, outputVlan);
......