mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-12-16 14:52:15 +01:00
ONOS Network Troubleshooting System
Newest Commit changes:
1. Add unit tests.
2. Fix review comments.
3. Add support to BUCK.
Could you please make a Code Review, we wish to hear anything from you :)
Thank you very much!
----------------------------------------------------
ONOS Network Troubleshooting System
Modularity design. In present, include these tow module:
1. Routing Loop Detection
Welcome your contribution for more modules in the future...
Beijing University of Posts and Telecommunications
new: withdraw blackhole tracing for redesign;
fix obvious checkstyle problem.
Change-Id: Id6d3aa0bc00c8da8ac046e6903f17cfdf954d919
This commit is contained in:
parent
0f4d63a2f3
commit
42e2344416
13
apps/network-troubleshoot/BUCK
Normal file
13
apps/network-troubleshoot/BUCK
Normal file
@ -0,0 +1,13 @@
|
||||
BUNDLES = [
|
||||
'//apps/network-troubleshoot/api:onos-apps-network-troubleshoot-api',
|
||||
'//apps/network-troubleshoot/cli:onos-apps-network-troubleshoot-cli',
|
||||
'//apps/network-troubleshoot/core:onos-apps-network-troubleshoot-core',
|
||||
]
|
||||
|
||||
onos_app (
|
||||
title = 'Network TroubleShoot SubSystem',
|
||||
description = 'ONOS Network TroubleShoot SubSystem',
|
||||
category = 'Core',
|
||||
url = 'https://wiki.onosproject.org/display/ONOS/Network+TroubleShooting+Module',
|
||||
included_bundles = BUNDLES,
|
||||
)
|
||||
12
apps/network-troubleshoot/api/BUCK
Normal file
12
apps/network-troubleshoot/api/BUCK
Normal file
@ -0,0 +1,12 @@
|
||||
COMPILE_DEPS = [
|
||||
'//lib:CORE_DEPS',
|
||||
]
|
||||
|
||||
TEST_DEPS = [
|
||||
'//lib:TEST_ADAPTERS',
|
||||
]
|
||||
|
||||
osgi_jar_with_tests (
|
||||
deps = COMPILE_DEPS,
|
||||
test_deps = TEST_DEPS,
|
||||
)
|
||||
45
apps/network-troubleshoot/api/pom.xml
Normal file
45
apps/network-troubleshoot/api/pom.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2014-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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot</artifactId>
|
||||
<version>1.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>onos-network-troubleshoot-api</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<description>ONOS Network TroubleShoot SubSystem API</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onlab-junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.base;
|
||||
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.HostId;
|
||||
import org.onosproject.net.flow.FlowEntry;
|
||||
import org.onosproject.net.flow.criteria.Criterion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Common utility functions and constants.
|
||||
*/
|
||||
public final class NetworkDiagnosticUtils {
|
||||
|
||||
private NetworkDiagnosticUtils() {
|
||||
// no instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of flow entries sorted by priority in descending order.
|
||||
*
|
||||
* @param flowEntries flow entries to be sorted
|
||||
* @return flow entries in descending order
|
||||
*/
|
||||
public static List<FlowEntry> sortFlowTable(Iterable<FlowEntry> flowEntries) {
|
||||
|
||||
List<FlowEntry> flows = new ArrayList<>();
|
||||
flowEntries.forEach(flows::add);
|
||||
|
||||
Collections.sort(flows,
|
||||
(f1, f2) -> f2.priority() - f1.priority());
|
||||
return flows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of match fields sorted by their types in ascending order.
|
||||
*
|
||||
* @param criterionSet the criteria to be sorted
|
||||
* @return the list of criteria in ascending order
|
||||
*/
|
||||
public static List<Criterion> sortCriteria(Set<Criterion> criterionSet) {
|
||||
|
||||
List<Criterion> array = new ArrayList<>(criterionSet);
|
||||
Collections.sort(array,
|
||||
(c1, c2) -> c1.type().compareTo(c2.type()));
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given connect point is a device point.
|
||||
*
|
||||
* @param connectPoint the connect point to be checked
|
||||
* @return true if the connect point is a device point
|
||||
*/
|
||||
public static boolean isDevice(ConnectPoint connectPoint) {
|
||||
return connectPoint.elementId() instanceof DeviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given connect point is a host point.
|
||||
*
|
||||
* @param connectPoint the connect point to be checked
|
||||
* @return true if the connect point is a host point
|
||||
*/
|
||||
public static boolean isHost(ConnectPoint connectPoint) {
|
||||
// TODO - not debug yet
|
||||
return connectPoint.elementId() instanceof HostId;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.base;
|
||||
|
||||
import org.onosproject.fnl.intf.NetworkAnomaly;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.flow.FlowEntry;
|
||||
import org.onosproject.net.flow.criteria.Criterion;
|
||||
import org.onosproject.net.flow.criteria.EthCriterion;
|
||||
import org.onosproject.net.flow.criteria.EthTypeCriterion;
|
||||
import org.onosproject.net.flow.criteria.IPCriterion;
|
||||
import org.onosproject.net.flow.criteria.IPDscpCriterion;
|
||||
import org.onosproject.net.flow.criteria.IPEcnCriterion;
|
||||
import org.onosproject.net.flow.criteria.IPProtocolCriterion;
|
||||
import org.onosproject.net.flow.criteria.PortCriterion;
|
||||
import org.onosproject.net.flow.criteria.TcpPortCriterion;
|
||||
import org.onosproject.net.flow.criteria.UdpPortCriterion;
|
||||
import org.onosproject.net.flow.criteria.VlanIdCriterion;
|
||||
import org.onosproject.net.flow.criteria.VlanPcpCriterion;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.onosproject.fnl.intf.NetworkAnomaly.Type.LOOP;
|
||||
import static org.onosproject.fnl.base.TsLoopPacket.SetHeaderResult.SETHEADER_FAILURE_NULL;
|
||||
import static org.onosproject.fnl.base.TsLoopPacket.SetHeaderResult.SETHEADER_OVERRIDE;
|
||||
import static org.onosproject.fnl.base.TsLoopPacket.SetHeaderResult.SETHEADER_SUCCESS;
|
||||
import static org.onosproject.net.flow.criteria.Criteria.*;
|
||||
|
||||
/**
|
||||
* Virtual packet for Default Loop Checking.
|
||||
*/
|
||||
public final class TsLoopPacket implements NetworkAnomaly {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static final String EOL = String.format("%n");
|
||||
private static final String LINE =
|
||||
EOL + "====================================================" + EOL;
|
||||
private static final String HDR_FMT = EOL + "---------- %s ----------" + EOL;
|
||||
private static final String LOOP_HEADER = makeHeader("Loop Header");
|
||||
private static final String LOOP_FLOW_ENTRIES = makeHeader("Loop Flow Entries");
|
||||
private static final String LOOP_LINKS = makeHeader("Loop Links");
|
||||
|
||||
private Map<Criterion.Type, Criterion> match;
|
||||
private Stack<FlowEntry> pathFlow;
|
||||
// when Upgrade, check to MAKE SURE it include just Link but not EdgeLink
|
||||
private Stack<Link> pathLink;
|
||||
|
||||
/**
|
||||
* Create an initial virtual packet inside for Loop Checking.
|
||||
*/
|
||||
private TsLoopPacket() {
|
||||
match = new HashMap<>();
|
||||
pathFlow = new Stack<>();
|
||||
pathLink = new Stack<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return LOOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the result of setting a header to virtual packet.
|
||||
*/
|
||||
public enum SetHeaderResult {
|
||||
/**
|
||||
* Set header successfully.
|
||||
*/
|
||||
SETHEADER_SUCCESS,
|
||||
|
||||
/**
|
||||
* Set header successfully but override old value.
|
||||
*/
|
||||
SETHEADER_OVERRIDE,
|
||||
|
||||
/**
|
||||
* Fail to set Header because NULL value.
|
||||
*/
|
||||
SETHEADER_FAILURE_NULL,
|
||||
|
||||
/**
|
||||
* Fail to set Header, but reason is not defined, defined in advance.
|
||||
*/
|
||||
SETHEADER_FAILURE
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new packet instance with the copied match fields.
|
||||
*
|
||||
* With hard-copied match fields, references to path flows and path links.
|
||||
*
|
||||
* @return new loop packet instance with the copied match fields
|
||||
*/
|
||||
public TsLoopPacket copyPacketMatch() {
|
||||
|
||||
TsLoopPacket newOne = new TsLoopPacket();
|
||||
|
||||
newOne.pathFlow = this.pathFlow;
|
||||
newOne.pathLink = this.pathLink;
|
||||
|
||||
Map<Criterion.Type, Criterion> m = newOne.match;
|
||||
|
||||
for (Map.Entry<Criterion.Type, Criterion> entry : this.match.entrySet()) {
|
||||
Criterion.Type k = entry.getKey();
|
||||
Criterion v = entry.getValue();
|
||||
|
||||
switch (k) {
|
||||
case IN_PORT:
|
||||
m.put(k, matchInPort(((PortCriterion) v).port()));
|
||||
break;
|
||||
case ETH_SRC: // At present, not support Ethernet mask (ONOS?)
|
||||
m.put(k, matchEthSrc(((EthCriterion) v).mac()));
|
||||
break;
|
||||
case ETH_DST: // At present, not support Ethernet mask (ONOS?)
|
||||
m.put(k, matchEthDst(((EthCriterion) v).mac()));
|
||||
break;
|
||||
case ETH_TYPE:
|
||||
m.put(k, matchEthType(((EthTypeCriterion) v).ethType()));
|
||||
break;
|
||||
case VLAN_VID: // At present, not support VLAN mask (ONOS?)
|
||||
m.put(k, matchVlanId(((VlanIdCriterion) v).vlanId()));
|
||||
break;
|
||||
case VLAN_PCP:
|
||||
m.put(k, matchVlanPcp(((VlanPcpCriterion) v).priority()));
|
||||
break;
|
||||
case IPV4_SRC:
|
||||
m.put(k, matchIPSrc(((IPCriterion) v).ip()));
|
||||
break;
|
||||
case IPV4_DST:
|
||||
m.put(k, matchIPDst(((IPCriterion) v).ip()));
|
||||
break;
|
||||
case IP_PROTO:
|
||||
m.put(k, matchIPProtocol(((IPProtocolCriterion) v).protocol()));
|
||||
break;
|
||||
case IP_DSCP: // can't be supported by now
|
||||
m.put(k, matchIPDscp(((IPDscpCriterion) v).ipDscp()));
|
||||
break;
|
||||
case IP_ECN: // can't be supported by now
|
||||
m.put(k, matchIPEcn(((IPEcnCriterion) v).ipEcn()));
|
||||
break;
|
||||
case TCP_SRC:
|
||||
m.put(k, matchTcpSrc(((TcpPortCriterion) v).tcpPort()));
|
||||
break;
|
||||
case TCP_DST:
|
||||
m.put(k, matchTcpDst(((TcpPortCriterion) v).tcpPort()));
|
||||
break;
|
||||
case UDP_SRC:
|
||||
m.put(k, matchUdpSrc(((UdpPortCriterion) v).udpPort()));
|
||||
break;
|
||||
case UDP_DST:
|
||||
m.put(k, matchUdpDst(((UdpPortCriterion) v).udpPort()));
|
||||
break;
|
||||
default: //can't be supported by OF1.0
|
||||
log.debug("{} can't be supported by OF1.0", k);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given criterion as a packet header field.
|
||||
*
|
||||
* @param criterion as packet header field
|
||||
* @return the result of set action
|
||||
*/
|
||||
public SetHeaderResult setHeader(Criterion criterion) {
|
||||
|
||||
if (criterion == null) {
|
||||
return SETHEADER_FAILURE_NULL;
|
||||
}
|
||||
|
||||
boolean hasKey = match.containsKey(criterion.type());
|
||||
|
||||
match.put(criterion.type(), criterion);
|
||||
|
||||
return hasKey ? SETHEADER_OVERRIDE : SETHEADER_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a packet header field by the designated header type.
|
||||
*
|
||||
* @param criterionType as packet header type
|
||||
* @return true, if packet contained the corresponding type of header;
|
||||
* false, otherwise
|
||||
*/
|
||||
public boolean delHeader(Criterion.Type criterionType) {
|
||||
return match.remove(criterionType) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a packet header field value by the designated header type.
|
||||
*
|
||||
* Returns null if the field does not exist.
|
||||
*
|
||||
* @param criterionType as packet header type
|
||||
* @return the packet header field value; may be null
|
||||
*/
|
||||
public Criterion getHeader(Criterion.Type criterionType) {
|
||||
return match.get(criterionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there is the type of header field in the packet.
|
||||
*
|
||||
* @param criterionType packet header type
|
||||
* @return true if the field exists; false otherwise
|
||||
*/
|
||||
public boolean headerExists(Criterion.Type criterionType) {
|
||||
return match.containsKey(criterionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the given flow entry onto the path flow stack.
|
||||
* Packet matches this entry in specific switch hop.
|
||||
*
|
||||
* @param entry the matched entry
|
||||
*/
|
||||
public void pushPathFlow(FlowEntry entry) {
|
||||
pathFlow.push(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops a FlowEntry from path flow entry stack.
|
||||
*/
|
||||
public void popPathFlow() {
|
||||
pathFlow.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns links in the path which the packet passes through.
|
||||
*
|
||||
* @return an iterator over the set of links
|
||||
*/
|
||||
public Iterator<Link> getPathLink() {
|
||||
return pathLink.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Link to path link list.
|
||||
* Packet goes through this link between two switches.
|
||||
*
|
||||
* @param link The link through which the packet go
|
||||
*/
|
||||
public void pushPathLink(Link link) {
|
||||
// TODO - need CPY link manual?
|
||||
pathLink.push(link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a Link from path link list.
|
||||
*/
|
||||
public void popPathLink() {
|
||||
pathLink.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the packet passed through the specific device.
|
||||
*
|
||||
* @param deviceId identify of the divice to test
|
||||
* @return true if packet passed through the specific device;
|
||||
* false otherwise
|
||||
*/
|
||||
public boolean isPassedDevice(DeviceId deviceId) {
|
||||
for (Link linkTemp : pathLink) {
|
||||
if (deviceId.equals(linkTemp.src().deviceId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IN_PORT header field of the packet.
|
||||
*
|
||||
* Attention:
|
||||
* IN_PORT field will be changed when packet goes into the next switch hop.
|
||||
*
|
||||
* @return a port criterion object.
|
||||
*/
|
||||
public PortCriterion getInport() {
|
||||
// TODO - check IN_PORT or IN_PHY_PORT
|
||||
return (PortCriterion) match.get(Criterion.Type.IN_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a loop packet instance with given Match Fields.
|
||||
*
|
||||
* Returns null,
|
||||
* whenever SetHeader_FAILURE or SETHEADER_FAILURE_NULL happened.
|
||||
*
|
||||
* @param criteria match field of one flow entry
|
||||
* @param collision as return value;
|
||||
* true, if criteria contain multiple ones with same type
|
||||
* @return a new loop packet instance; may be null
|
||||
*/
|
||||
public static TsLoopPacket matchBuilder(Iterable<Criterion> criteria,
|
||||
TsReturn<Boolean> collision) {
|
||||
|
||||
if (null != collision) {
|
||||
collision.setValue(false);
|
||||
}
|
||||
|
||||
TsLoopPacket pkt = new TsLoopPacket();
|
||||
|
||||
for (Criterion criterion : criteria) {
|
||||
|
||||
SetHeaderResult ret = pkt.setHeader(criterion);
|
||||
|
||||
if (SETHEADER_SUCCESS == ret) {
|
||||
//TODO - in the future, we may need to resolve this condition
|
||||
} else if (SETHEADER_OVERRIDE == ret) {
|
||||
if (null != collision) {
|
||||
collision.setValue(true);
|
||||
}
|
||||
} else { // SetHeader_FAILURE or SetHeader_FAILURE_NULL
|
||||
pkt = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hands in the header of virtual packet one by one.
|
||||
* Let the header go up through every layer of recursion.
|
||||
* It is called when a loop is discovered.
|
||||
*
|
||||
* @param loopPkt virtual packet that will trigger Loop Storm
|
||||
*/
|
||||
public void handInLoopMatch(TsLoopPacket loopPkt) {
|
||||
match = loopPkt.match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the path link and path flow structures.
|
||||
* And initializing the path flow with the gicen flow entry.
|
||||
*
|
||||
* @param firstEntry the flow entry from which this packet is built
|
||||
*/
|
||||
public void resetLinkFlow(FlowEntry firstEntry) {
|
||||
pathLink = new Stack<>();
|
||||
pathFlow = new Stack<>();
|
||||
pathFlow.push(firstEntry);
|
||||
}
|
||||
|
||||
private static String makeHeader(String title) {
|
||||
return String.format(HDR_FMT, title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a multi-line string representation of this loop packet instance.
|
||||
*
|
||||
* @return formatted string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder me = new StringBuilder();
|
||||
|
||||
me.append(LINE);
|
||||
|
||||
me.append(LOOP_HEADER);
|
||||
|
||||
List<Criterion> criteria = new ArrayList<>(match.values());
|
||||
Collections.sort(criteria, (o1, o2) -> o1.type().compareTo(o2.type()));
|
||||
|
||||
for (Criterion c : criteria) {
|
||||
me.append(c).append(EOL);
|
||||
}
|
||||
|
||||
me.append(LOOP_FLOW_ENTRIES);
|
||||
|
||||
for (FlowEntry flow : pathFlow) {
|
||||
me.append(flow).append(EOL);
|
||||
}
|
||||
|
||||
me.append(LOOP_LINKS);
|
||||
|
||||
for (Link l : pathLink) {
|
||||
me.append(l).append(EOL);
|
||||
}
|
||||
|
||||
return me.toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.base;
|
||||
|
||||
/**
|
||||
* Represents an additional value that a caller may pass to a method.
|
||||
* Be filled in by the called method.
|
||||
*
|
||||
* Used as an extra return value.
|
||||
*
|
||||
* @param <M> the class of expected return value
|
||||
*/
|
||||
public final class TsReturn<M> {
|
||||
private M ret;
|
||||
|
||||
/**
|
||||
* Sets the value of this instance.
|
||||
*
|
||||
* @param value the value to set
|
||||
*/
|
||||
public void setValue(M value) {
|
||||
ret = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this instance.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public M getValue() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the value has been set.
|
||||
* Generally, if setValue() has not been invoked,
|
||||
* the value will not be present (i.e. null).
|
||||
*
|
||||
* @return true, if ret is present;
|
||||
* false, otherwise
|
||||
*/
|
||||
public boolean isPresent() {
|
||||
return ret != null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base and tool classes used in troubleshooting algorithms.
|
||||
*/
|
||||
package org.onosproject.fnl.base;
|
||||
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.fnl.intf;
|
||||
|
||||
/**
|
||||
* Result of network anomaly diagnosis.
|
||||
*/
|
||||
public interface NetworkAnomaly {
|
||||
|
||||
/**
|
||||
* Returns the type of anomaly result.
|
||||
*
|
||||
* @return the type of anomaly
|
||||
*/
|
||||
Type type();
|
||||
|
||||
/**
|
||||
* Represents anomaly types.
|
||||
*/
|
||||
enum Type {
|
||||
|
||||
/**
|
||||
* Packets round among several devices with several forwarding entries.
|
||||
*
|
||||
* Routing loops.
|
||||
*/
|
||||
LOOP
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.intf;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provide algorithms or methods to diagnose network.
|
||||
*
|
||||
* Strategy Pattern.
|
||||
*/
|
||||
public interface NetworkDiagnostic {
|
||||
|
||||
/**
|
||||
* Checks for and returns all corresponding anomalies.
|
||||
* An empty set is returned if there are no anomalies.
|
||||
*
|
||||
* @return the set of all corresponding anomalies; may be empty
|
||||
*/
|
||||
Set<NetworkAnomaly> findAnomalies();
|
||||
|
||||
/**
|
||||
* Returns the type of diagnostic.
|
||||
*
|
||||
* @return the type of diagnostic
|
||||
*/
|
||||
Type type();
|
||||
|
||||
/**
|
||||
* Represents diagnostic types.
|
||||
*/
|
||||
enum Type {
|
||||
|
||||
/**
|
||||
* Packets round among several devices with several forwarding entries.
|
||||
*
|
||||
* Routing loops.
|
||||
*/
|
||||
LOOP
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.intf;
|
||||
|
||||
import org.onosproject.fnl.intf.NetworkDiagnostic.Type;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Network Troubleshooting Core Service.
|
||||
*/
|
||||
public interface NetworkDiagnosticService {
|
||||
|
||||
/**
|
||||
* Checks for and returns all registered kinds of network anomalies.
|
||||
* An empty set is returned if there are no anomalies found.
|
||||
*
|
||||
* @return all discovered anomalies; may be empty
|
||||
*/
|
||||
Set<NetworkAnomaly> findAnomalies();
|
||||
|
||||
/**
|
||||
* Checks for and returns the specific kind of network anomalies.
|
||||
* <p>
|
||||
* An empty set is returned if there is no anomaly of specific type,
|
||||
* or there is no diagnostic of specific type.
|
||||
*
|
||||
* @return the specific kind of anomalies; may be empty
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks for and returns the specific type of network anomalies.
|
||||
* <p>
|
||||
* An empty set is returned if there is no anomaly of specific type,
|
||||
* or there is no diagnostic of specific type.
|
||||
*
|
||||
* @param type the type of network anomalies
|
||||
* @return the specific kind of anomalies; may be empty
|
||||
*/
|
||||
Set<NetworkAnomaly> findAnomalies(Type type);
|
||||
|
||||
/**
|
||||
* Registers the specified diagnostic module with the service.
|
||||
*
|
||||
* Each diagnostic type can have only one module,
|
||||
* and previous one will be removed.
|
||||
*
|
||||
* @param diagnostic an instance of class implemented NetworkDiagnostic
|
||||
*/
|
||||
void register(NetworkDiagnostic diagnostic);
|
||||
|
||||
/**
|
||||
* Unregisters the specified diagnostic module form the service.
|
||||
*
|
||||
* @param diagnostic diagnostic module to be removed
|
||||
* @return true if the module existed before and has been removed
|
||||
* successfully; false otherwise
|
||||
*/
|
||||
boolean unregister(NetworkDiagnostic diagnostic);
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base interfaces for Network Troubleshooting SubSystem.
|
||||
*/
|
||||
package org.onosproject.fnl.intf;
|
||||
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.base;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Unit Tests for TsReturn class.
|
||||
*/
|
||||
public class TsReturnTest {
|
||||
|
||||
private static final boolean OLD_BOOLEAN_EXAMPLE = false;
|
||||
private static final boolean NEW_BOOLEAN_EXAMPLE = true;
|
||||
private static final int OLD_INTEGER_EXAMPLE = 7181;
|
||||
private static final int NEW_INTEGER_EXAMPLE = 1355;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPresent() {
|
||||
TsReturn<Boolean> bool = new TsReturn<>();
|
||||
assertFalse(bool.isPresent());
|
||||
|
||||
bool.setValue(NEW_BOOLEAN_EXAMPLE);
|
||||
assertTrue(bool.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoleReturnBoolean() {
|
||||
TsReturn<Boolean> bool = new TsReturn<>();
|
||||
bool.setValue(OLD_BOOLEAN_EXAMPLE);
|
||||
|
||||
Boolean oldValue = bool.getValue();
|
||||
changeBoolean(bool);
|
||||
Boolean newValue = bool.getValue();
|
||||
|
||||
assertNotSame(oldValue, newValue);
|
||||
assertEquals(newValue, NEW_BOOLEAN_EXAMPLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoleReturnInteger() {
|
||||
TsReturn<Integer> integer = new TsReturn<>();
|
||||
integer.setValue(OLD_INTEGER_EXAMPLE);
|
||||
|
||||
Integer oldValue = integer.getValue();
|
||||
changeInteger(integer);
|
||||
Integer newValue = integer.getValue();
|
||||
|
||||
assertNotSame(oldValue, newValue);
|
||||
assertEquals(newValue.intValue(), NEW_INTEGER_EXAMPLE);
|
||||
}
|
||||
|
||||
private void changeBoolean(TsReturn bool) {
|
||||
bool.setValue(NEW_BOOLEAN_EXAMPLE);
|
||||
}
|
||||
|
||||
private void changeInteger(TsReturn integer) {
|
||||
integer.setValue(NEW_INTEGER_EXAMPLE);
|
||||
}
|
||||
}
|
||||
30
apps/network-troubleshoot/app/app.xml
Normal file
30
apps/network-troubleshoot/app/app.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<app name="org.onosproject.fnl.Network.Troubleshoot" category="Core" version="${project.version}"
|
||||
title="Network TroubleShoot SubSystem"
|
||||
originUrl="http://www.bupt.edu.cn" origin="FNLab, BUPT"
|
||||
features="${project.artifactId}"
|
||||
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
|
||||
url="https://wiki.onosproject.org/display/ONOS/Network+TroubleShooting+Module">
|
||||
|
||||
<description>${project.description}</description>
|
||||
|
||||
<artifact>mvn:${project.groupId}/onos-network-troubleshoot-api/${project.version}</artifact>
|
||||
<artifact>mvn:${project.groupId}/onos-network-troubleshoot-core/${project.version}</artifact>
|
||||
<artifact>mvn:${project.groupId}/onos-network-troubleshoot-cli/${project.version}</artifact>
|
||||
|
||||
</app>
|
||||
29
apps/network-troubleshoot/app/features.xml
Normal file
29
apps/network-troubleshoot/app/features.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
|
||||
name="${project.artifactId}-${project.version}">
|
||||
|
||||
<feature name="${project.artifactId}" version="${project.version}"
|
||||
description="${project.description}">
|
||||
|
||||
<bundle>mvn:${project.groupId}/onos-network-troubleshoot-api/${project.version}</bundle>
|
||||
<bundle>mvn:${project.groupId}/onos-network-troubleshoot-core/${project.version}</bundle>
|
||||
<bundle>mvn:${project.groupId}/onos-network-troubleshoot-cli/${project.version}</bundle>
|
||||
|
||||
</feature>
|
||||
|
||||
</features>
|
||||
56
apps/network-troubleshoot/app/pom.xml
Normal file
56
apps/network-troubleshoot/app/pom.xml
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot</artifactId>
|
||||
<version>1.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>onos-network-troubleshoot-app</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>ONOS Network TroubleShoot SubSystem</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot-cli</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
18
apps/network-troubleshoot/cli/BUCK
Normal file
18
apps/network-troubleshoot/cli/BUCK
Normal file
@ -0,0 +1,18 @@
|
||||
COMPILE_DEPS = [
|
||||
'//lib:CORE_DEPS',
|
||||
'//lib:org.apache.karaf.shell.console',
|
||||
'//cli:onos-cli',
|
||||
# '//lib:org.apache.karaf.shell.console',
|
||||
# '//incubator/api:onos-incubator-api',
|
||||
# '//cli:onos-cli',
|
||||
# '//utils/rest:onlab-rest',
|
||||
# '//lib:javax.ws.rs-api',
|
||||
# '//utils/osgi:onlab-osgi',
|
||||
# '//core/store/serializers:onos-core-serializers',
|
||||
'//apps/network-troubleshoot/api:onos-apps-network-troubleshoot-api',
|
||||
]
|
||||
|
||||
osgi_jar_with_tests (
|
||||
deps = COMPILE_DEPS,
|
||||
import_packages = '*,org.onosproject.cli.net',
|
||||
)
|
||||
56
apps/network-troubleshoot/cli/pom.xml
Normal file
56
apps/network-troubleshoot/cli/pom.xml
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot</artifactId>
|
||||
<version>1.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>onos-network-troubleshoot-cli</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<description>ONOS Network TroubleShoot SubSystem</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- for CLI command -->
|
||||
<dependency>
|
||||
<groupId>org.apache.karaf.shell</groupId>
|
||||
<artifactId>org.apache.karaf.shell.console</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-cli</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.fnl.cli;
|
||||
|
||||
import org.apache.karaf.shell.commands.Command;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnosticService;
|
||||
|
||||
/**
|
||||
* Search for all types of network anomalies.
|
||||
*/
|
||||
@Command(scope = "onos",
|
||||
name = "ts-all-anomalies",
|
||||
description = "search all types of network anomalies once",
|
||||
detailedDescription = "Report different information " +
|
||||
"for specific type of anomalies.")
|
||||
public class TsAllAnomalies extends AbstractShellCommand {
|
||||
|
||||
@Override
|
||||
protected void execute() {
|
||||
NetworkDiagnosticService service = getService(NetworkDiagnosticService.class);
|
||||
|
||||
service.findAnomalies().forEach(a -> print(a.toString()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.cli;
|
||||
|
||||
import org.apache.karaf.shell.commands.Command;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnostic;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnosticService;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.host.HostService;
|
||||
import org.onosproject.net.link.LinkService;
|
||||
|
||||
/**
|
||||
* Search for all potential routing loops.
|
||||
*/
|
||||
@Command(scope = "onos",
|
||||
name = "ts-check-loops",
|
||||
description = "Check if there are some routing loops in the network",
|
||||
detailedDescription = "Report the header of loop-trigger packet, " +
|
||||
"DevicesIds and FlowEntries.")
|
||||
public class TsCheckLoop extends AbstractShellCommand {
|
||||
|
||||
@Override
|
||||
protected void execute() {
|
||||
NetworkDiagnosticService service = getService(NetworkDiagnosticService.class);
|
||||
|
||||
DeviceService ds = getService(DeviceService.class);
|
||||
HostService hs = getService(HostService.class);
|
||||
FlowRuleService frs = getService(FlowRuleService.class);
|
||||
LinkService ls = getService(LinkService.class);
|
||||
|
||||
service.findAnomalies(NetworkDiagnostic.Type.LOOP)
|
||||
.forEach(loop -> print(loop.toString()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2015-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The CLI commands for checking specific network trouble.
|
||||
*/
|
||||
package org.onosproject.fnl.cli;
|
||||
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
|
||||
<command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
|
||||
<command>
|
||||
<action class="org.onosproject.fnl.cli.TsAllAnomalies" />
|
||||
</command>
|
||||
<command>
|
||||
<action class="org.onosproject.fnl.cli.TsCheckLoop" />
|
||||
</command>
|
||||
</command-bundle>
|
||||
</blueprint>
|
||||
17
apps/network-troubleshoot/core/BUCK
Normal file
17
apps/network-troubleshoot/core/BUCK
Normal file
@ -0,0 +1,17 @@
|
||||
COMPILE_DEPS = [
|
||||
'//lib:CORE_DEPS',
|
||||
'//incubator/api:onos-incubator-api',
|
||||
# '//core/store/serializers:onos-core-serializers',
|
||||
'//apps/network-troubleshoot/api:onos-apps-network-troubleshoot-api',
|
||||
]
|
||||
|
||||
TEST_DEPS = [
|
||||
'//lib:TEST_ADAPTERS',
|
||||
'//utils/osgi:onlab-osgi-tests',
|
||||
'//incubator/api:onos-incubator-api-tests',
|
||||
]
|
||||
|
||||
osgi_jar_with_tests (
|
||||
deps = COMPILE_DEPS,
|
||||
test_deps = TEST_DEPS,
|
||||
)
|
||||
76
apps/network-troubleshoot/core/pom.xml
Normal file
76
apps/network-troubleshoot/core/pom.xml
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot</artifactId>
|
||||
<version>1.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>onos-network-troubleshoot-core</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<description>ONOS Network TroubleShoot SubSystem</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-network-troubleshoot-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- for component config -->
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.compendium</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onlab-junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-library</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.impl;
|
||||
|
||||
import org.onlab.packet.IpPrefix;
|
||||
import org.onosproject.fnl.intf.NetworkAnomaly;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnostic;
|
||||
import org.onosproject.fnl.base.TsLoopPacket;
|
||||
import org.onosproject.fnl.base.TsReturn;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.Device;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.flow.FlowEntry;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.flow.criteria.Criterion;
|
||||
import org.onosproject.net.flow.criteria.EthTypeCriterion;
|
||||
import org.onosproject.net.flow.criteria.IPCriterion;
|
||||
import org.onosproject.net.flow.criteria.IPProtocolCriterion;
|
||||
import org.onosproject.net.flow.criteria.PortCriterion;
|
||||
import org.onosproject.net.flow.instructions.Instruction;
|
||||
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
|
||||
import org.onosproject.net.host.HostService;
|
||||
import org.onosproject.net.link.LinkService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.onlab.packet.EthType.EtherType.IPV4;
|
||||
import static org.onlab.packet.EthType.EtherType.VLAN;
|
||||
import static org.onosproject.fnl.base.NetworkDiagnosticUtils.isDevice;
|
||||
import static org.onosproject.fnl.base.NetworkDiagnosticUtils.sortCriteria;
|
||||
import static org.onosproject.fnl.base.NetworkDiagnosticUtils.sortFlowTable;
|
||||
import static org.onosproject.fnl.base.TsLoopPacket.matchBuilder;
|
||||
import static org.onosproject.fnl.intf.NetworkDiagnostic.Type.LOOP;
|
||||
import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
|
||||
import static org.onosproject.net.flow.criteria.Criteria.matchInPort;
|
||||
import static org.onosproject.net.flow.criteria.Criterion.Type.ETH_TYPE;
|
||||
import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
|
||||
import static org.onosproject.net.flow.criteria.Criterion.Type.IP_PROTO;
|
||||
|
||||
/**
|
||||
* Loop Checking Diagnostic Implementation.
|
||||
*
|
||||
* Strategy Pattern.
|
||||
*/
|
||||
public class DefaultCheckLoop implements NetworkDiagnostic {
|
||||
|
||||
private static final int IP_PROTO_TCP_TS = 6;
|
||||
private static final int IP_PROTO_UDP_TS = 17;
|
||||
|
||||
private static final String E_CANNOT_HANDLE = "can not handle {} now.";
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final DeviceService deviceService;
|
||||
private final HostService hostService;
|
||||
private final FlowRuleService flowRuleService;
|
||||
private final LinkService linkService;
|
||||
|
||||
|
||||
private Map<DeviceId, Device> deviceInfo;
|
||||
private Map<DeviceId, Iterable<FlowEntry>> flowEntryInfo;
|
||||
private Set<Device> accessDevices;
|
||||
|
||||
//conventionally used by tsGetEgressLinks()
|
||||
private Map<DeviceId, Set<Link>> egressLinkInfo;
|
||||
|
||||
//Two below are hot data in checking process.
|
||||
private Set<NetworkAnomaly> loops;
|
||||
private Set<DeviceId> excludeDeviceId;
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of Loop Checking algorithm module.
|
||||
*
|
||||
* @param ds reference of DeviceService
|
||||
* @param hs reference of HostService
|
||||
* @param frs reference of FlowRuleService
|
||||
* @param ls reference of LinkService
|
||||
*/
|
||||
public DefaultCheckLoop(DeviceService ds,
|
||||
HostService hs,
|
||||
FlowRuleService frs,
|
||||
LinkService ls) {
|
||||
checkNotNull(ds, "DeviceService cannot be null");
|
||||
checkNotNull(hs, "HostService cannot be null");
|
||||
checkNotNull(frs, "FlowRuleService cannot be null");
|
||||
checkNotNull(ls, "LinkService cannot be null");
|
||||
|
||||
deviceService = ds;
|
||||
hostService = hs;
|
||||
flowRuleService = frs;
|
||||
linkService = ls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for loops and returns any that were found.
|
||||
* An empty set is returned if there are no loops.
|
||||
*
|
||||
* @return the set of loops; may be empty
|
||||
*/
|
||||
@Override
|
||||
public Set<NetworkAnomaly> findAnomalies() {
|
||||
return findLoop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return LOOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter of the loop checking algorithm.
|
||||
*
|
||||
* @return the set of loop results; empty, if there is no loop
|
||||
*/
|
||||
private Set<NetworkAnomaly> findLoop() {
|
||||
|
||||
getNetworkSnapshot();
|
||||
|
||||
loops = new HashSet<>();
|
||||
excludeDeviceId = new HashSet<>();
|
||||
|
||||
for (Device device : accessDevices) {
|
||||
if (excludeDeviceId.contains(device.id())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
List<FlowEntry> availableFlowEntries = new ArrayList<>();
|
||||
|
||||
flowEntryInfo.get(device.id()).forEach(flowEntry -> {
|
||||
if (flowEntry.state() == ADDED) {
|
||||
availableFlowEntries.add(flowEntry);
|
||||
}
|
||||
});
|
||||
|
||||
List<FlowEntry> sortedFlowEntries = sortFlowTable(availableFlowEntries);
|
||||
|
||||
|
||||
for (FlowEntry flow : sortedFlowEntries) {
|
||||
|
||||
TsLoopPacket pkt =
|
||||
matchBuilder(flow.selector().criteria(), null);
|
||||
|
||||
pkt.pushPathFlow(flow);
|
||||
|
||||
List<Instruction> inst = flow.treatment().immediate();
|
||||
|
||||
for (Instruction instOne : inst) {
|
||||
// Attention !!!
|
||||
// if you would like to modify the code here,
|
||||
// please MAKE VERY SURE that you are clear with
|
||||
// the relationship of any invoked methods, and
|
||||
// the relationship of params which are passed in and out.
|
||||
processOneInstruction(instOne, device.id(),
|
||||
null, pkt, true, flow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - avoid two-hop LOOP
|
||||
|
||||
// TODO - another clean operations
|
||||
|
||||
return loops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate one by one at switch hops.
|
||||
* Return whether we discover a Loop now or not.
|
||||
*
|
||||
* When flows form a loop,
|
||||
* pkt is also a return value indicating the loop header.
|
||||
*
|
||||
* @param deviceId the device needed to be checked
|
||||
* @param pkt virtual packet forwarded by switches
|
||||
* @return true if a loop is discovered
|
||||
*/
|
||||
private boolean matchDeviceFlows(DeviceId deviceId, TsLoopPacket pkt) {
|
||||
if (pkt.isPassedDevice(deviceId)) {
|
||||
return true; // Attention: pkt should be held outside
|
||||
}
|
||||
|
||||
|
||||
List<FlowEntry> availableFlowEntries = new ArrayList<>();
|
||||
|
||||
flowEntryInfo.get(deviceId).forEach(flowEntry -> {
|
||||
if (flowEntry.state() == ADDED) {
|
||||
availableFlowEntries.add(flowEntry);
|
||||
}
|
||||
});
|
||||
|
||||
List<FlowEntry> sortedFlowEntries = sortFlowTable(availableFlowEntries);
|
||||
|
||||
|
||||
for (FlowEntry flowEntry : sortedFlowEntries) {
|
||||
TsReturn<Boolean> isBigger = new TsReturn<>();
|
||||
TsLoopPacket newPkt = pkt.copyPacketMatch();
|
||||
|
||||
if (!matchAndAddFlowEntry(flowEntry, newPkt, isBigger)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
newPkt.pushPathFlow(flowEntry);
|
||||
// no need to popPathFlow(),
|
||||
// because we will drop this newPkt, and copy pkt again
|
||||
|
||||
for (Instruction instOne : flowEntry.treatment().immediate()) {
|
||||
// Attention !!!
|
||||
// if you would like to modify the code here,
|
||||
// please MAKE VERY SURE that you are clear with
|
||||
// the relationship of any invoked methods, and
|
||||
// the relationship of params which are passed in and out.
|
||||
if (processOneInstruction(instOne, deviceId,
|
||||
pkt, newPkt, false, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
newPkt.popPathFlow();
|
||||
|
||||
if (!isBigger.getValue()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one of every instructions.
|
||||
*
|
||||
* The isFindLoop should be true if it is invoked by findLoop method,
|
||||
* and be false if it is invoked by matchDeviceFlows method.
|
||||
*
|
||||
* @param instOne the instruction to be processed
|
||||
* @param currentDeviceId id of the device we are now in
|
||||
* @param initPkt the packet before being copied
|
||||
* @param matchedPkt the packet which matched the flow entry,
|
||||
* to which this instruction belongs
|
||||
* @param isFindLoop indicate if it is invoked by findLoop method
|
||||
* @param firstEntry the flow entry from which the packet is generated
|
||||
* @return true, if a loop is discovered;
|
||||
* false, 1. invoked by matchDeviceFlows method, and detected no loop;
|
||||
* 2. invoked by findLoop method
|
||||
*/
|
||||
private boolean processOneInstruction(Instruction instOne,
|
||||
DeviceId currentDeviceId,
|
||||
TsLoopPacket initPkt,
|
||||
TsLoopPacket matchedPkt,
|
||||
boolean isFindLoop,
|
||||
FlowEntry firstEntry) {
|
||||
if (isFindLoop) {
|
||||
checkArgument(initPkt == null,
|
||||
"initPkt is not null, while isFindLoop is true.");
|
||||
} else {
|
||||
checkArgument(firstEntry == null,
|
||||
"firstEntry is not null, while isFindLoop is false.");
|
||||
}
|
||||
|
||||
|
||||
Instruction.Type type = instOne.type();
|
||||
switch (type) {
|
||||
case L2MODIFICATION:
|
||||
//TODO - modify the L2 header of virtual packet
|
||||
log.warn(E_CANNOT_HANDLE, type);
|
||||
break;
|
||||
case L3MODIFICATION:
|
||||
//TODO - modify the L3 header of virtual packet
|
||||
log.warn(E_CANNOT_HANDLE, type);
|
||||
break;
|
||||
case L4MODIFICATION:
|
||||
//TODO - modify the L4 header of virtual packet
|
||||
log.warn(E_CANNOT_HANDLE, type);
|
||||
break;
|
||||
case OUTPUT:
|
||||
if (processOneOutputInstruction(instOne, currentDeviceId,
|
||||
initPkt, matchedPkt, isFindLoop, firstEntry)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log.error("Can't process this type of instruction: {} now.",
|
||||
instOne.type());
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one output instruction.
|
||||
*
|
||||
* Params are passed from processOneInstruction directly,
|
||||
* and obey the same rules.
|
||||
*
|
||||
* @param instOne the instruction to be processed
|
||||
* @param currentDeviceId id of the device we are now in
|
||||
* @param initPkt the packet before being copied
|
||||
* @param matchedPkt the packet which matched the flow entry,
|
||||
* to which this instruction belongs
|
||||
* @param isFindLoop indicate if it is invoked by findLoop method
|
||||
* @param firstEntry the flow entry from which the packet is generated
|
||||
* @return true, if a loop is discovered;
|
||||
* false, 1. invoked by matchDeviceFlows method, and detected no loop;
|
||||
* 2. invoked by findLoop method
|
||||
*/
|
||||
private boolean processOneOutputInstruction(Instruction instOne,
|
||||
DeviceId currentDeviceId,
|
||||
TsLoopPacket initPkt,
|
||||
TsLoopPacket matchedPkt,
|
||||
boolean isFindLoop,
|
||||
FlowEntry firstEntry) {
|
||||
OutputInstruction instOutput = (OutputInstruction) instOne;
|
||||
PortNumber instPort = instOutput.port();
|
||||
|
||||
if (!instPort.isLogical()) {
|
||||
// single OUTPUT - NIC or normal port
|
||||
|
||||
Set<Link> dstLink = tsGetEgressLinks(
|
||||
new ConnectPoint(currentDeviceId, instPort));
|
||||
if (!dstLink.isEmpty()) {
|
||||
|
||||
// TODO - now, just deal with the first destination.
|
||||
// will there be more destinations?
|
||||
|
||||
Link dstThisLink = dstLink.iterator().next();
|
||||
ConnectPoint dstPoint = dstThisLink.dst();
|
||||
|
||||
// check output to devices only (output to a host is normal)
|
||||
if (isDevice(dstPoint)) {
|
||||
PortCriterion oldInPort =
|
||||
updatePktInportPerHop(matchedPkt, dstPoint);
|
||||
matchedPkt.pushPathLink(dstThisLink);
|
||||
TsLoopPacket newNewPkt = matchedPkt.copyPacketMatch();
|
||||
|
||||
boolean loopFound =
|
||||
matchDeviceFlows(dstPoint.deviceId(), newNewPkt);
|
||||
if (isFindLoop) {
|
||||
if (loopFound) {
|
||||
loops.add(newNewPkt);
|
||||
updateExcludeDeviceSet(newNewPkt);
|
||||
}
|
||||
matchedPkt.resetLinkFlow(firstEntry);
|
||||
} else {
|
||||
if (loopFound) {
|
||||
initPkt.handInLoopMatch(newNewPkt);
|
||||
return true;
|
||||
}
|
||||
matchedPkt.popPathLink();
|
||||
}
|
||||
restorePktInportPerHop(matchedPkt, oldInPort);
|
||||
}
|
||||
} else {
|
||||
if (!isFindLoop) {
|
||||
//TODO - NEED
|
||||
log.warn("no link connecting at device {}, port {}",
|
||||
currentDeviceId, instPort);
|
||||
}
|
||||
}
|
||||
} else if (instPort.equals(PortNumber.IN_PORT)) {
|
||||
//TODO - in the future,
|
||||
// we may need to resolve this condition 1
|
||||
log.warn("can not handle {} port now.", PortNumber.IN_PORT);
|
||||
} else if (instPort.equals(PortNumber.NORMAL) ||
|
||||
instPort.equals(PortNumber.FLOOD) ||
|
||||
instPort.equals(PortNumber.ALL)) {
|
||||
//TODO - in the future,
|
||||
// we may need to resolve this condition 2
|
||||
log.warn("can not handle {}/{}/{} now.",
|
||||
PortNumber.NORMAL, PortNumber.FLOOD, PortNumber.ALL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateExcludeDeviceSet(TsLoopPacket loopPkt) {
|
||||
Iterator<Link> iter = loopPkt.getPathLink();
|
||||
while (iter.hasNext()) {
|
||||
excludeDeviceId.add(iter.next().src().deviceId());
|
||||
}
|
||||
}
|
||||
|
||||
private PortCriterion updatePktInportPerHop(TsLoopPacket oldPkt,
|
||||
ConnectPoint dstPoint) {
|
||||
|
||||
PortCriterion inPort = oldPkt.getInport();
|
||||
PortCriterion oldInPort =
|
||||
null != inPort ? (PortCriterion) matchInPort(inPort.port()) : null;
|
||||
// TODO - check - if it really copies this object
|
||||
|
||||
oldPkt.setHeader(matchInPort(dstPoint.port()));
|
||||
|
||||
return oldInPort;
|
||||
}
|
||||
|
||||
private void restorePktInportPerHop(TsLoopPacket pkt,
|
||||
PortCriterion oldInPort) {
|
||||
if (oldInPort == null) {
|
||||
pkt.delHeader(IN_PORT);
|
||||
} else {
|
||||
pkt.setHeader(oldInPort);
|
||||
}
|
||||
}
|
||||
|
||||
private void getNetworkSnapshot() {
|
||||
deviceInfo = new HashMap<>();
|
||||
deviceService.getDevices().forEach(d -> deviceInfo.put(d.id(), d));
|
||||
|
||||
flowEntryInfo = new HashMap<>();
|
||||
deviceInfo.keySet().forEach(id ->
|
||||
flowEntryInfo.put(id, flowRuleService.getFlowEntries(id)));
|
||||
|
||||
egressLinkInfo = new HashMap<>();
|
||||
deviceInfo.keySet().forEach(id ->
|
||||
egressLinkInfo.put(id, linkService.getDeviceEgressLinks(id)));
|
||||
|
||||
accessDevices = new HashSet<>();
|
||||
hostService.getHosts().forEach(h ->
|
||||
accessDevices.add(deviceInfo.get(h.location().deviceId())));
|
||||
}
|
||||
|
||||
private Set<Link> tsGetEgressLinks(ConnectPoint point) {
|
||||
Set<Link> portEgressLink = new HashSet<>();
|
||||
DeviceId deviceId = point.deviceId();
|
||||
|
||||
portEgressLink.addAll(
|
||||
//all egress links
|
||||
egressLinkInfo.get(deviceId)
|
||||
.stream()
|
||||
.filter(l -> l.src().equals(point))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return portEgressLink;
|
||||
}
|
||||
|
||||
private boolean matchAndAddFlowEntry(FlowEntry flowEntry,
|
||||
TsLoopPacket pkt,
|
||||
TsReturn<Boolean> isBigger) {
|
||||
isBigger.setValue(false);
|
||||
|
||||
List<Criterion> criterionArray =
|
||||
sortCriteria(flowEntry.selector().criteria());
|
||||
|
||||
for (Criterion criterion : criterionArray) {
|
||||
// TODO - advance
|
||||
switch (criterion.type()) {
|
||||
case IN_PORT:
|
||||
case ETH_SRC:
|
||||
// At present, not support Ethernet mask (ONOS?)
|
||||
case ETH_DST:
|
||||
// At present, not support Ethernet mask (ONOS?)
|
||||
case ETH_TYPE:
|
||||
if (!matchAddExactly(pkt, criterion, isBigger)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case VLAN_VID:
|
||||
// At present, not support VLAN mask (ONOS?)
|
||||
case VLAN_PCP:
|
||||
if (!pkt.headerExists(ETH_TYPE) ||
|
||||
!((EthTypeCriterion) pkt.getHeader(ETH_TYPE))
|
||||
.ethType().equals(VLAN.ethType())) {
|
||||
return false;
|
||||
}
|
||||
if (!matchAddExactly(pkt, criterion, isBigger)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case IPV4_SRC:
|
||||
case IPV4_DST:
|
||||
if (!pkt.headerExists(ETH_TYPE) ||
|
||||
!((EthTypeCriterion) pkt.getHeader(ETH_TYPE))
|
||||
.ethType().equals(IPV4.ethType())) {
|
||||
return false;
|
||||
}
|
||||
if (!matchAddIPV4(pkt, criterion, isBigger)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case IP_PROTO:
|
||||
if (!pkt.headerExists(ETH_TYPE) ||
|
||||
!((EthTypeCriterion) pkt.getHeader(ETH_TYPE))
|
||||
.ethType().equals(IPV4.ethType())) {
|
||||
return false;
|
||||
}
|
||||
if (!matchAddExactly(pkt, criterion, isBigger)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case IP_DSCP:
|
||||
// TODO: 10/28/16 support IP_DSCP match field
|
||||
break;
|
||||
case IP_ECN:
|
||||
// TODO: 10/28/16 support IP_DSCP match field
|
||||
break;
|
||||
case TCP_SRC:
|
||||
case TCP_DST:
|
||||
if (!pkt.headerExists(IP_PROTO) ||
|
||||
IP_PROTO_TCP_TS !=
|
||||
((IPProtocolCriterion)
|
||||
pkt.getHeader(IP_PROTO))
|
||||
.protocol()
|
||||
) {
|
||||
// has TCP match requirement, but can't afford TCP
|
||||
return false;
|
||||
}
|
||||
// in this "for" loop
|
||||
// avoid IP_PROTO locates after TCP_*
|
||||
if (!matchAddExactly(pkt, criterion, isBigger)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case UDP_SRC:
|
||||
case UDP_DST:
|
||||
if (!pkt.headerExists(IP_PROTO) ||
|
||||
IP_PROTO_UDP_TS !=
|
||||
((IPProtocolCriterion)
|
||||
pkt.getHeader(IP_PROTO))
|
||||
.protocol()
|
||||
) {
|
||||
// has UDP match requirement, but can't afford UDP
|
||||
return false;
|
||||
}
|
||||
// in this "for" loop
|
||||
// avoid IP_PROTO locates after UDP_*
|
||||
if (!matchAddExactly(pkt, criterion, isBigger)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log.debug("{} can't be supported by OF1.0",
|
||||
criterion.type());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean matchAddExactly(TsLoopPacket pkt,
|
||||
Criterion criterion,
|
||||
TsReturn<Boolean> isBigger) {
|
||||
|
||||
if (pkt.headerExists(criterion.type())) {
|
||||
if (!pkt.getHeader(criterion.type()).equals(criterion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// TODO - check if it is IN_PORT or IN_PHY_PORT, should be strict
|
||||
pkt.setHeader(criterion);
|
||||
isBigger.setValue(true);
|
||||
}
|
||||
|
||||
return true; // should put it here
|
||||
}
|
||||
|
||||
// before invoking this, MUST insure EtherType is IPv4.
|
||||
private boolean matchAddIPV4(TsLoopPacket pkt,
|
||||
Criterion criterion,
|
||||
TsReturn<Boolean> isBigger) {
|
||||
|
||||
if (pkt.headerExists(criterion.type())) {
|
||||
|
||||
IpPrefix ipFlow = ((IPCriterion) criterion).ip();
|
||||
IpPrefix ipPkt =
|
||||
((IPCriterion) pkt.getHeader(criterion.type())).ip();
|
||||
|
||||
// attention - the order below is important
|
||||
if (ipFlow.equals(ipPkt)) {
|
||||
// shoot
|
||||
|
||||
} else if (ipFlow.contains(ipPkt)) {
|
||||
// shoot, pkt is more exact than flowEntry
|
||||
|
||||
} else if (ipPkt.contains(ipFlow)) {
|
||||
// pkt should be changed to be more exact
|
||||
pkt.setHeader(criterion);
|
||||
isBigger.setValue(true);
|
||||
} else {
|
||||
// match fail
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// attention the order of criteria in "for" loop
|
||||
pkt.setHeader(criterion);
|
||||
isBigger.setValue(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.impl;
|
||||
|
||||
import org.apache.felix.scr.annotations.Component;
|
||||
import org.apache.felix.scr.annotations.Modified;
|
||||
import org.apache.felix.scr.annotations.Reference;
|
||||
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
||||
import org.apache.felix.scr.annotations.Service;
|
||||
import org.apache.felix.scr.annotations.Property;
|
||||
import org.apache.felix.scr.annotations.Activate;
|
||||
import org.apache.felix.scr.annotations.Deactivate;
|
||||
import org.onlab.util.Tools;
|
||||
import org.onosproject.cfg.ComponentConfigService;
|
||||
import org.onosproject.fnl.intf.NetworkAnomaly;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnostic;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnostic.Type;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnosticService;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.core.CoreService;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.host.HostService;
|
||||
import org.onosproject.net.link.LinkService;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Default implementation of the Network Troubleshooting Core Service.
|
||||
*
|
||||
* It is simply modularized at present.
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
@Service
|
||||
public class NetworkDiagnosticManager implements NetworkDiagnosticService {
|
||||
|
||||
/**
|
||||
* Name of Network Troubleshooting Application.
|
||||
*/
|
||||
public static final String NTS_APP_NAME =
|
||||
"org.onosproject.FNL.Network-Troubleshoot";
|
||||
|
||||
private static final String PROPERTY_AUTO_REGISTER_DIAG =
|
||||
"autoRegisterDefaultDiagnostics";
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected CoreService coreService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected ComponentConfigService cfgService;
|
||||
|
||||
|
||||
// ------ service below is for auto register ------
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected DeviceService ds;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected HostService hs;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected FlowRuleService frs;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected LinkService ls;
|
||||
|
||||
|
||||
@Property(name = PROPERTY_AUTO_REGISTER_DIAG, boolValue = true,
|
||||
label = "Automatically register all of default diagnostic modules.")
|
||||
private boolean autoRegister = true;
|
||||
|
||||
|
||||
private ApplicationId appId;
|
||||
|
||||
private Map<Type, NetworkDiagnostic> diagnostics = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
@Activate
|
||||
protected void activate(ComponentContext context) {
|
||||
appId = coreService.registerApplication(NTS_APP_NAME);
|
||||
|
||||
cfgService.registerProperties(getClass());
|
||||
readConfiguration(context);
|
||||
|
||||
autoRegisterDiagnostics();
|
||||
|
||||
log.info("Started");
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
protected void deactivate() {
|
||||
unregisterDiagnostics();
|
||||
log.info("Stopped");
|
||||
}
|
||||
|
||||
@Modified
|
||||
protected void modified(ComponentContext context) {
|
||||
|
||||
readConfiguration(context);
|
||||
|
||||
// We should not register default diagnostics automatically
|
||||
// in the Modify(), because that will erase the result of
|
||||
// dynamic extension, run-time and custom diagnostics.
|
||||
//
|
||||
// And, using this modified() is to avoid deactivate-activate procedure.
|
||||
|
||||
log.info("Modified");
|
||||
}
|
||||
|
||||
private void readConfiguration(ComponentContext context) {
|
||||
Dictionary<?, ?> properties = context.getProperties();
|
||||
|
||||
Boolean autoRegisterEnabled =
|
||||
Tools.isPropertyEnabled(properties, PROPERTY_AUTO_REGISTER_DIAG);
|
||||
if (autoRegisterEnabled == null) {
|
||||
log.warn("Auto Register is not configured, " +
|
||||
"using current value of {}", autoRegister);
|
||||
} else {
|
||||
autoRegister = autoRegisterEnabled;
|
||||
log.info("Configured. Auto Register is {}",
|
||||
autoRegister ? "enabled" : "disabled");
|
||||
}
|
||||
}
|
||||
|
||||
private void autoRegisterDiagnostics() {
|
||||
if (!autoRegister) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 10/26/16 future new default diagnostics should be added here.
|
||||
register(new DefaultCheckLoop(ds, hs, frs, ls));
|
||||
}
|
||||
|
||||
private void unregisterDiagnostics() {
|
||||
// TODO: 10/27/16 improve this for parallel.
|
||||
diagnostics.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NetworkAnomaly> findAnomalies() {
|
||||
Set<NetworkAnomaly> allAnomalies = new HashSet<>();
|
||||
|
||||
diagnostics.forEach((type, diag) ->
|
||||
allAnomalies.addAll(diag.findAnomalies()));
|
||||
|
||||
return allAnomalies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NetworkAnomaly> findAnomalies(Type type) {
|
||||
checkNotNull(type, "NetworkAnomaly Type cannot be null");
|
||||
|
||||
Set<NetworkAnomaly> anomalies = new HashSet<>();
|
||||
|
||||
NetworkDiagnostic diag = diagnostics.get(type);
|
||||
if (diag == null) {
|
||||
log.warn("no anomalies of type {} found", type);
|
||||
return anomalies;
|
||||
}
|
||||
|
||||
anomalies.addAll(diag.findAnomalies());
|
||||
|
||||
return anomalies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(NetworkDiagnostic diag) {
|
||||
checkNotNull(diag, "Diagnostic cannot be null");
|
||||
|
||||
NetworkDiagnostic oldDiag = diagnostics.put(diag.type(), diag);
|
||||
|
||||
if (oldDiag != null) {
|
||||
log.warn("previous diagnostic {} is replaced by {},",
|
||||
oldDiag.getClass(), diag.getClass());
|
||||
} else {
|
||||
log.info("Register {} type module: {}",
|
||||
diag.type(), diag.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregister(NetworkDiagnostic diag) {
|
||||
checkNotNull(diag, "Diagnostic cannot be null");
|
||||
|
||||
return diagnostics.remove(diag.type(), diag);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2015-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Implement of troubleshoot Core and specific checking modules.
|
||||
*/
|
||||
package org.onosproject.fnl.impl;
|
||||
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright 2015-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.fnl.impl;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.onlab.packet.ChassisId;
|
||||
import org.onlab.packet.IPv4;
|
||||
import org.onlab.packet.IpPrefix;
|
||||
import org.onlab.packet.MacAddress;
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onosproject.fnl.intf.NetworkAnomaly;
|
||||
import org.onosproject.fnl.intf.NetworkDiagnostic;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DefaultDevice;
|
||||
import org.onosproject.net.DefaultHost;
|
||||
import org.onosproject.net.DefaultLink;
|
||||
import org.onosproject.net.Device;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Host;
|
||||
import org.onosproject.net.HostId;
|
||||
import org.onosproject.net.HostLocation;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.flow.DefaultFlowEntry;
|
||||
import org.onosproject.net.flow.DefaultFlowRule;
|
||||
import org.onosproject.net.flow.DefaultTrafficSelector;
|
||||
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||
import org.onosproject.net.flow.FlowEntry;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.net.flow.TrafficSelector;
|
||||
import org.onosproject.net.flow.TrafficTreatment;
|
||||
import org.onosproject.net.host.HostService;
|
||||
import org.onosproject.net.link.LinkService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
|
||||
import static org.onlab.packet.EthType.EtherType.IPV4;
|
||||
import static org.onlab.packet.TpPort.tpPort;
|
||||
import static org.onosproject.net.DefaultAnnotations.EMPTY;
|
||||
import static org.onosproject.net.Link.State.ACTIVE;
|
||||
import static org.onosproject.net.Link.Type.DIRECT;
|
||||
import static org.onosproject.net.PortNumber.portNumber;
|
||||
import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
|
||||
import static org.onosproject.net.provider.ProviderId.NONE;
|
||||
|
||||
/**
|
||||
* Unit Tests for DefaultCheckLoop class.
|
||||
*/
|
||||
public class DefaultCheckLoopTest {
|
||||
|
||||
private NetworkDiagnostic defaultCheckLoop;
|
||||
|
||||
private DeviceService ds;
|
||||
private HostService hs;
|
||||
private FlowRuleService frs;
|
||||
private LinkService ls;
|
||||
|
||||
private List<Device> devices;
|
||||
private List<Host> hosts;
|
||||
private Map<DeviceId, Set<Link>> egressLinks;
|
||||
private Map<DeviceId, List<FlowEntry>> flowEntries;
|
||||
|
||||
|
||||
private static final DeviceId DEVICE_ID_A = DeviceId.deviceId("of:000000000000000A");
|
||||
private static final DeviceId DEVICE_ID_B = DeviceId.deviceId("of:000000000000000B");
|
||||
private static final DeviceId DEVICE_ID_C = DeviceId.deviceId("of:000000000000000C");
|
||||
private static final DeviceId DEVICE_ID_D = DeviceId.deviceId("of:000000000000000D");
|
||||
private static final DeviceId DEVICE_ID_E = DeviceId.deviceId("of:E000000000000000");
|
||||
private static final DeviceId DEVICE_ID_F = DeviceId.deviceId("of:F000000000000000");
|
||||
private static final DeviceId DEVICE_ID_G = DeviceId.deviceId("of:A000000000000000");
|
||||
|
||||
private static final String HOSTID_EXAMPLE = "12:34:56:78:9A:BC/1355";
|
||||
private static final long FLOWRULE_COOKIE_EXAMPLE = 708;
|
||||
private static final int FLOWRULE_PRIORITY_EXAMPLE = 738;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
ds = EasyMock.createMock(DeviceService.class);
|
||||
hs = EasyMock.createMock(HostService.class);
|
||||
frs = EasyMock.createMock(FlowRuleService.class);
|
||||
ls = EasyMock.createMock(LinkService.class);
|
||||
|
||||
defaultCheckLoop = new DefaultCheckLoop(ds, hs, frs, ls);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindLoops() {
|
||||
produceTopoDevices();
|
||||
produceTopoHosts();
|
||||
produceTopoLinks();
|
||||
produceFlowEntries();
|
||||
|
||||
initMock();
|
||||
|
||||
Set<NetworkAnomaly> loops = defaultCheckLoop.findAnomalies();
|
||||
assertThat(loops, hasSize(1));
|
||||
}
|
||||
|
||||
private void initMock() {
|
||||
expect(ds.getDevices()).andReturn(devices).anyTimes();
|
||||
replay(ds);
|
||||
|
||||
expect(hs.getHosts()).andReturn(hosts).anyTimes();
|
||||
replay(hs);
|
||||
|
||||
// --- init flow rule service ---
|
||||
|
||||
expect(frs.getFlowEntries(DEVICE_ID_A))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_A)).anyTimes();
|
||||
expect(frs.getFlowEntries(DEVICE_ID_B))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_B)).anyTimes();
|
||||
expect(frs.getFlowEntries(DEVICE_ID_C))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_C)).anyTimes();
|
||||
expect(frs.getFlowEntries(DEVICE_ID_D))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_D)).anyTimes();
|
||||
expect(frs.getFlowEntries(DEVICE_ID_E))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_E)).anyTimes();
|
||||
expect(frs.getFlowEntries(DEVICE_ID_F))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_F)).anyTimes();
|
||||
expect(frs.getFlowEntries(DEVICE_ID_G))
|
||||
.andReturn(flowEntries.get(DEVICE_ID_G)).anyTimes();
|
||||
replay(frs);
|
||||
|
||||
// --- init link service ---
|
||||
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_A))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_A)).anyTimes();
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_B))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_B)).anyTimes();
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_C))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_C)).anyTimes();
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_D))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_D)).anyTimes();
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_E))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_E)).anyTimes();
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_F))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_F)).anyTimes();
|
||||
expect(ls.getDeviceEgressLinks(DEVICE_ID_G))
|
||||
.andReturn(egressLinks.get(DEVICE_ID_G)).anyTimes();
|
||||
replay(ls);
|
||||
}
|
||||
|
||||
private void produceTopoDevices() {
|
||||
devices = new ArrayList<>();
|
||||
devices.add(produceOneDevice(DEVICE_ID_A));
|
||||
devices.add(produceOneDevice(DEVICE_ID_B));
|
||||
devices.add(produceOneDevice(DEVICE_ID_C));
|
||||
devices.add(produceOneDevice(DEVICE_ID_D));
|
||||
devices.add(produceOneDevice(DEVICE_ID_E));
|
||||
devices.add(produceOneDevice(DEVICE_ID_F));
|
||||
devices.add(produceOneDevice(DEVICE_ID_G));
|
||||
}
|
||||
|
||||
private Device produceOneDevice(DeviceId dpid) {
|
||||
return new DefaultDevice(NONE, dpid,
|
||||
Device.Type.SWITCH, "", "", "", "", new ChassisId(),
|
||||
EMPTY);
|
||||
}
|
||||
|
||||
private void produceTopoHosts() {
|
||||
hosts = new ArrayList<>();
|
||||
hosts.add(produceOneHost(DEVICE_ID_A, 3));
|
||||
hosts.add(produceOneHost(DEVICE_ID_B, 3));
|
||||
hosts.add(produceOneHost(DEVICE_ID_D, 3));
|
||||
hosts.add(produceOneHost(DEVICE_ID_F, 2));
|
||||
hosts.add(produceOneHost(DEVICE_ID_F, 3));
|
||||
hosts.add(produceOneHost(DEVICE_ID_G, 1));
|
||||
hosts.add(produceOneHost(DEVICE_ID_G, 3));
|
||||
}
|
||||
|
||||
private Host produceOneHost(DeviceId dpid, int port) {
|
||||
return new DefaultHost(NONE, HostId.hostId(HOSTID_EXAMPLE),
|
||||
MacAddress.valueOf(0), VlanId.vlanId(),
|
||||
new HostLocation(dpid, portNumber(port), 1),
|
||||
ImmutableSet.of(), EMPTY);
|
||||
}
|
||||
|
||||
private void produceTopoLinks() {
|
||||
egressLinks = new HashMap<>();
|
||||
|
||||
Set<Link> el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_A, 1, DEVICE_ID_B, 1));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_A, 2, DEVICE_ID_D, 2));
|
||||
egressLinks.put(DEVICE_ID_A, el);
|
||||
|
||||
el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_B, 1, DEVICE_ID_A, 1));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_B, 2, DEVICE_ID_C, 2));
|
||||
egressLinks.put(DEVICE_ID_B, el);
|
||||
|
||||
el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_C, 1, DEVICE_ID_D, 1));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_C, 2, DEVICE_ID_B, 2));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_C, 3, DEVICE_ID_E, 3));
|
||||
egressLinks.put(DEVICE_ID_C, el);
|
||||
|
||||
el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_D, 1, DEVICE_ID_C, 1));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_D, 2, DEVICE_ID_A, 2));
|
||||
egressLinks.put(DEVICE_ID_D, el);
|
||||
|
||||
el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_E, 1, DEVICE_ID_F, 1));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_E, 2, DEVICE_ID_G, 2));
|
||||
el.add(produceOneEgressLink(DEVICE_ID_E, 3, DEVICE_ID_C, 3));
|
||||
egressLinks.put(DEVICE_ID_E, el);
|
||||
|
||||
el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_F, 1, DEVICE_ID_E, 1));
|
||||
egressLinks.put(DEVICE_ID_F, el);
|
||||
|
||||
el = new HashSet<>();
|
||||
el.add(produceOneEgressLink(DEVICE_ID_G, 2, DEVICE_ID_E, 2));
|
||||
egressLinks.put(DEVICE_ID_G, el);
|
||||
}
|
||||
|
||||
private Link produceOneEgressLink(DeviceId srcId, int srcPort, DeviceId dstId, int dstPort) {
|
||||
return DefaultLink.builder()
|
||||
.providerId(NONE)
|
||||
.src(new ConnectPoint(srcId, portNumber(srcPort)))
|
||||
.dst(new ConnectPoint(dstId, portNumber(dstPort)))
|
||||
.type(DIRECT)
|
||||
.state(ACTIVE)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void produceFlowEntries() {
|
||||
flowEntries = new HashMap<>();
|
||||
|
||||
List<FlowEntry> fe = new ArrayList<>();
|
||||
fe.add(produceOneFlowEntry(DEVICE_ID_A, 2));
|
||||
flowEntries.put(DEVICE_ID_A, fe);
|
||||
|
||||
fe = new ArrayList<>();
|
||||
fe.add(produceOneFlowEntry(DEVICE_ID_D, 1));
|
||||
flowEntries.put(DEVICE_ID_D, fe);
|
||||
|
||||
fe = new ArrayList<>();
|
||||
fe.add(produceOneFlowEntry(DEVICE_ID_C, 2));
|
||||
flowEntries.put(DEVICE_ID_C, fe);
|
||||
|
||||
fe = new ArrayList<>();
|
||||
fe.add(produceOneFlowEntry(DEVICE_ID_B, 1));
|
||||
flowEntries.put(DEVICE_ID_B, fe);
|
||||
|
||||
flowEntries.put(DEVICE_ID_E, new ArrayList<>());
|
||||
flowEntries.put(DEVICE_ID_F, new ArrayList<>());
|
||||
flowEntries.put(DEVICE_ID_G, new ArrayList<>());
|
||||
|
||||
}
|
||||
|
||||
private FlowEntry produceOneFlowEntry(DeviceId dpid, int outPort) {
|
||||
|
||||
TrafficSelector.Builder sb = DefaultTrafficSelector.builder()
|
||||
.matchEthType(IPV4.ethType().toShort())
|
||||
.matchIPDst(IpPrefix.valueOf("10.0.0.0/8"))
|
||||
.matchIPProtocol(IPv4.PROTOCOL_TCP)
|
||||
.matchTcpDst(tpPort(22));
|
||||
|
||||
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
|
||||
.setOutput(portNumber(outPort));
|
||||
|
||||
return new DefaultFlowEntry(DefaultFlowRule.builder()
|
||||
.withPriority(FLOWRULE_PRIORITY_EXAMPLE).forDevice(dpid).forTable(0)
|
||||
.withCookie(FLOWRULE_COOKIE_EXAMPLE)
|
||||
.withSelector(sb.build()).withTreatment(tb.build())
|
||||
.makePermanent().build(), ADDED);
|
||||
}
|
||||
}
|
||||
41
apps/network-troubleshoot/pom.xml
Normal file
41
apps/network-troubleshoot/pom.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2015-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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-apps</artifactId>
|
||||
<version>1.10.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>onos-network-troubleshoot</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>ONOS Network TroubleShoot SubSystem</description>
|
||||
|
||||
<modules>
|
||||
<module>api</module>
|
||||
<module>cli</module>
|
||||
<module>core</module>
|
||||
<module>app</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@ -89,6 +89,7 @@
|
||||
<module>intentsync</module>
|
||||
<module>mappingmanagement</module>
|
||||
<module>yang</module>
|
||||
<module>network-troubleshoot</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
||||
@ -190,7 +190,8 @@ ONOS_APPS = [
|
||||
'//apps/flowspec-api:onos-apps-flowspec-api-oar',
|
||||
'//apps/yang:onos-apps-yang-oar',
|
||||
'//apps/yang-gui:onos-apps-yang-gui-oar',
|
||||
'//apps/cord-support:onos-apps-cord-support-oar'
|
||||
'//apps/cord-support:onos-apps-cord-support-oar',
|
||||
'//apps/network-troubleshoot:onos-apps-network-troubleshoot-oar'
|
||||
]
|
||||
|
||||
APP_JARS = [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user