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";
......
......@@ -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);
......