import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.inventory.IInventoryService;
import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
public class Activator extends ComponentActivatorAbstractBase {
* ComponentActivatorAbstractBase.
*
*/
+ @Override
public void init() {
}
* cleanup done by ComponentActivatorAbstractBase
*
*/
+ @Override
public void destroy() {
}
* @return The list of implementations the bundle will support,
* in Global version
*/
+ @Override
protected Object[] getGlobalImplementations() {
Object[] res = { ConnectionManager.class };
return res;
* @param imp implementation to be configured
* @param containerName container on which the configuration happens
*/
+ @Override
protected void configureGlobalInstance(Component c, Object imp) {
if (imp.equals(ConnectionManager.class)) {
Dictionary<String, Object> props = new Hashtable<String, Object>();
c.add(createServiceDependency().setService(IConnectionService.class)
.setCallbacks("setConnectionService", "unsetConnectionService")
.setRequired(true));
+ c.add(createServiceDependency().setService(IInventoryService.class, "(scope=Global)")
+ .setCallbacks("setInventoryService", "unsetInventoryService")
+ .setRequired(true));
}
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.core.Property;
import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IInventoryService;
import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
private IConnectionService connectionService;
private Thread connectionEventThread;
private BlockingQueue<ConnectionMgmtEvent> connectionEvents;
+ private IInventoryService inventoryService;
public void setClusterServices(IClusterGlobalServices i) {
this.clusterServices = i;
}
}
+ public void setInventoryService(IInventoryService service) {
+ logger.trace("Got inventory service set request {}", service);
+ this.inventoryService = service;
+ }
+
+ public void unsetInventoryService(IInventoryService service) {
+ logger.trace("Got a service UNset request");
+ this.inventoryService = null;
+ }
+
+ private void getInventories() {
+ Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
+ for (Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
+ Node node = entry.getKey();
+ logger.debug("getInventories for node:{}", new Object[] { node });
+ Map<String, Property> propMap = entry.getValue();
+ Set<Property> props = new HashSet<Property>();
+ for (Property property : propMap.values()) {
+ props.add(property);
+ }
+ updateNode(node, UpdateType.ADDED, props);
+ }
+
+ Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
+ for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
+ Map<String, Property> propMap = entry.getValue();
+ Set<Property> props = new HashSet<Property>();
+ for (Property property : propMap.values()) {
+ props.add(property);
+ }
+ updateNodeConnector(entry.getKey(), UpdateType.ADDED, props);
+ }
+ }
+
public void started() {
connectionEventThread = new Thread(new EventHandler(), "ConnectionEvent Thread");
connectionEventThread.start();
registerWithOSGIConsole();
notifyClusterViewChanged();
+ // Should pull the Inventory updates in case we missed it
+ getInventories();
}
public void init() {
* with this controller to take hold of a Node.
*/
if (isConnectionAllowed(node)) {
- if (!nodeConnections.replace(node, oldControllers, newControllers)) {
+ if (oldControllers == null || !nodeConnections.replace(node, oldControllers, newControllers)) {
clusterServices.trollback();
try {
Thread.sleep(100);
} catch ( InterruptedException e) {}
- log.debug("Replace failed... old={} with new={} for {} to {}", oldControllers.toString(), newControllers.toString(),
- controller.getHostAddress(), node.toString());
+ log.debug("Retrying ... {} with {}", controller.getHostAddress(), node.toString());
return putNodeToController(node, controller);
} else {
log.debug("Replace successful old={} with new={} for {} to {}", oldControllers.toString(), newControllers.toString(),
#!/bin/bash
-[[ -z ${JAVA_HOME} ]] && echo "Need to set JAVA_HOME environment variable" && exit -1;
-[[ ! -x ${JAVA_HOME}/bin/java ]] && echo "Cannot find an executable \
-JVM at path ${JAVA_HOME}/bin/java check your JAVA_HOME" && exit -1;
-
platform='unknown'
unamestr=`uname`
if [[ "$unamestr" == 'Linux' ]]; then
PHYS_DIR=`pwd -P`
RESULT=$PHYS_DIR/$TARGET_FILE
fullpath=$RESULT
+
+ [[ -z ${JAVA_HOME} ]] && [[ -x "/usr/libexec/java_home" ]] && export JAVA_HOME=`/usr/libexec/java_home -v 1.7`;
+
fi
+[[ -z ${JAVA_HOME} ]] && echo "Need to set JAVA_HOME environment variable" && exit -1;
+[[ ! -x ${JAVA_HOME}/bin/java ]] && echo "Cannot find an executable \
+JVM at path ${JAVA_HOME}/bin/java check your JAVA_HOME" && exit -1;
+
basedir=`dirname ${fullpath}`
function usage {
public FlowEntry mergeWith(ContainerFlow containerFlow) {
Match myMatch = flow.getMatch();
- // Based on this flow direction, rearrange the match
- Match match = containerFlow.getMatch();
+ Match filter = containerFlow.getMatch();
// Merge
- myMatch.mergeWithFilter(match);
+ Match merge = myMatch.mergeWithFilter(filter);
// Replace this Flow's match with merged version
- flow.setMatch(myMatch);
+ flow.setMatch(merge);
return this;
}
.append("dstNodeConnector",
nodeConnectorType_2 + "|" + nodeConnectorId_2 + "@" + nodeType_2 + "|" + nodeId_2);
// execute HTTP request and verify response code
- result = getJsonResult(baseURL + "/userLink", "POST", jo.toString());
+ result = getJsonResult(baseURL + "/user-link", "POST", jo.toString());
Assert.assertTrue(httpResponseCode == 201);
// === test GET method for getUserLinks()
- result = getJsonResult(baseURL + "/userLink", "GET");
+ result = getJsonResult(baseURL + "/user-link", "GET");
Assert.assertTrue(httpResponseCode == 200);
if (debugMsg) {
System.out.println("result:" + result);
// === test DELETE method for deleteUserLink()
String userName = "userLink_1";
- result = getJsonResult(baseURL + "/userLink/" + userName, "DELETE");
+ result = getJsonResult(baseURL + "/user-link/" + userName, "DELETE");
Assert.assertTrue(httpResponseCode == 200);
// execute another getUserLinks() request to verify that userLink_1 is
// removed
- result = getJsonResult(baseURL + "/userLink", "GET");
+ result = getJsonResult(baseURL + "/user-link", "GET");
Assert.assertTrue(httpResponseCode == 200);
if (debugMsg) {
System.out.println("result:" + result);
* Retrieve the Topology
*
* @param containerName
- * The container for which we want to retrieve the topology
+ * The container for which we want to retrieve the topology (Eg. 'default')
*
* @return A List of EdgeProps each EdgeProp represent an Edge of the grap
* with the corresponding properties attached to it.
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * RequestURL:
+ * http://localhost:8080/controller/nb/v2/topology/default
+ *
+ * Response in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><topology><edgeProperties><edge><tailNodeConnector id="2" type="OF"><node id="00:00:00:00:00:00:00:02" type="OF"/></tailNodeConnector><headNodeConnector id="2" type="OF"><node id="00:00:00:00:00:00:00:51" type="OF"/></headNodeConnector></edge><properties><state><value>1</value></state><config><value>1</value></config><name><value>C1_2-L2_2</value></name><timeStamp><value>1377279422032</value><name>creation</name></timeStamp></properties></edgeProperties><edgeProperties><edge><tailNodeConnector id="2" type="OF"><node id="00:00:00:00:00:00:00:51" type="OF"/></tailNodeConnector><headNodeConnector id="2" type="OF"><node id="00:00:00:00:00:00:00:02" type="OF"/></headNodeConnector></edge><properties><state><value>1</value></state><name><value>L2_2-C1_2</value></name><config><value>1</value></config><timeStamp><value>1377279423564</value><name>creation</name></timeStamp></properties></edgeProperties></topology>
+ *
+ * Response in JSON:
+ * {"edgeProperties":[{"edge":{"tailNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:02","@type":"OF"}},"headNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:51","@type":"OF"}}},"properties":{"timeStamp":{"value":"1377278961017","name":"creation"}}},{"edge":{"tailNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:51","@type":"OF"}},"headNodeConnector":{"@id":"2","@type":"OF","node":{"@id":"00:00:00:00:00:00:00:02","@type":"OF"}}},"properties":{"timeStamp":{"value":"1377278961018","name":"creation"}}}]}
+ *
+ * </pre>
*/
@Path("/{containerName}")
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@TypeHint(Topology.class)
- @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
+ @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
public Topology getTopology(@PathParam("containerName") String containerName) {
if (!NorthboundUtils.isAuthorized(
* Retrieve the user configured links
*
* @param containerName
- * The container for which we want to retrieve the user links
+ * The container for which we want to retrieve the user links (Eg. 'default')
*
* @return A List of user configured links
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * RequestURL:
+ * http://localhost:8080/controller/nb/v2/topology/default/user-link
+ *
+ * Response in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><topologyUserLinks><userLinks><status>Success</status><name>link1</name><srcNodeConnector>OF|2@OF|00:00:00:00:00:00:00:02</srcNodeConnector><dstNodeConnector>OF|2@OF|00:00:00:00:00:00:00:51</dstNodeConnector></userLinks></topologyUserLinks>
+ *
+ * Response in JSON:
+ * {"userLinks":{"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}}
+ *
+ * </pre>
*/
- @Path("/{containerName}/userLink")
+ @Path("/{containerName}/user-link")
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@TypeHint(TopologyUserLinks.class)
- @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name passed was not found") })
+ @StatusCodes({ @ResponseCode(code = 404, condition = "The Container Name was not found") })
public TopologyUserLinks getUserLinks(
@PathParam("containerName") String containerName) {
* Add an User Link
*
* @param containerName
- * Name of the Container. The base Container is "default".
+ * Name of the Container (Eg. 'default')
* @param TopologyUserLinkConfig
* in JSON or XML format
* @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * RequestURL:
+ * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1-content
+ *
+ * Request in XML:
+ * <?xml version="1.0" encoding="UTF-8" standalone="yes"?><topologyUserLinks><status>Success</status><name>link1</name><srcNodeConnector>OF|2@OF|00:00:00:00:00:00:00:02</srcNodeConnector><dstNodeConnector>OF|2@OF|00:00:00:00:00:00:00:51</dstNodeConnector></topologyUserLinks>
+ *
+ * Request in JSON:
+ * {"status":"Success","name":"link1","srcNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:02","dstNodeConnector":"OF|2@OF|00:00:00:00:00:00:00:51"}
+ *
+ * </pre>
*/
-
- @Path("/{containerName}/userLink")
+ @Path("/{containerName}/user-link")
@POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@StatusCodes({
@ResponseCode(code = 201, condition = "User Link added successfully"),
- @ResponseCode(code = 404, condition = "The Container Name passed was not found"),
+ @ResponseCode(code = 404, condition = "The Container Name was not found"),
@ResponseCode(code = 409, condition = "Failed to add User Link due to Conflicting Name"),
@ResponseCode(code = 500, condition = "Failed to add User Link. Failure Reason included in HTTP Error response"),
@ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
* Delete an User Link
*
* @param containerName
- * Name of the Container. The base Container is "default".
+ * Name of the Container (Eg. 'default')
* @param name
- * Name of the Link Configuration
+ * Name of the Link Configuration (Eg. 'config1')
* @return Response as dictated by the HTTP Response Status code
+ *
+ * <pre>
+ *
+ * Example:
+ *
+ * RequestURL:
+ * http://localhost:8080/controller/nb/v2/topology/default/user-link/config1
+ *
+ * </pre>
*/
-
- @Path("/{containerName}/userLink/{name}")
+ @Path("/{containerName}/user-link/{name}")
@DELETE
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@StatusCodes({
@ResponseCode(code = 200, condition = "Operation successful"),
@ResponseCode(code = 404, condition = "The Container Name or Link Configuration Name was not found"),
}
throw new ResourceNotFoundException(ret.getDescription());
}
-
}
* are done by the ComponentActivatorAbstractBase.
*
*/
+ @Override
public void init() {
Node.NodeIDType.registerIDType("STUB", Integer.class);
NodeConnector.NodeConnectorIDType.registerIDType("STUB", Integer.class, "STUB");
* ComponentActivatorAbstractBase
*
*/
+ @Override
public void destroy() {
Node.NodeIDType.unRegisterIDType("STUB");
NodeConnector.NodeConnectorIDType.unRegisterIDType("STUB");
* instantiated in order to get an fully working implementation
* Object
*/
+ @Override
public Object[] getImplementations() {
Object[] res = { ReadService.class, InventoryService.class };
return res;
* per-container different behavior if needed, usually should not
* be the case though.
*/
+ @Override
public void configureInstance(Component c, Object imp, String containerName) {
if (imp.equals(ReadService.class)) {
// export the service to be used by SAL
}
}
+ @Override
public Object[] getGlobalImplementations() {
- Object[] res = { FlowProgrammerService.class, StubNodeFactory.class, StubNodeConnectorFactory.class };
+ Object[] res =
+ {
+ FlowProgrammerService.class,
+ StubNodeFactory.class,
+ StubNodeConnectorFactory.class,
+ InventoryService.class };
return res;
}
+ @Override
public void configureGlobalInstance(Component c, Object imp){
if (imp.equals(FlowProgrammerService.class)) {
// export the service to be used by SAL
props.put("protocolName", "STUB");
c.setInterface(INodeConnectorFactory.class.getName(), props);
}
-
+ if (imp.equals(InventoryService.class)) {
+ // export the service to be used by SAL
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ // Set the protocolPluginType property which will be used
+ // by SAL
+ props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), "STUB");
+ props.put("scope", "Global");
+ c.setInterface(IPluginInInventoryService.class.getName(), props);
+ c.add(createServiceDependency().setService(IPluginOutInventoryService.class, "(scope=Global)")
+ .setCallbacks("setPluginOutInventoryServices", "unsetPluginOutInventoryServices")
+ .setRequired(true));
+ }
}
}
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import org.apache.felix.dm.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.opendaylight.controller.sal.core.Actions;
import org.opendaylight.controller.sal.core.Bandwidth;
import org.opendaylight.controller.sal.core.Buffers;
import org.opendaylight.controller.sal.core.State;
import org.opendaylight.controller.sal.core.Tables;
import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.controller.sal.core.UpdateType;
import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
import org.opendaylight.controller.sal.utils.NodeCreator;
import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
// global
// container
// only
+ private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
+ new CopyOnWriteArraySet<IPluginOutInventoryService>();
+
+ public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
+ logger.trace("Got a service set request {}", service);
+ if (this.pluginOutInventoryServices != null) {
+ this.pluginOutInventoryServices.add(service);
+ }
+ }
+
+ public void unsetPluginOutInventoryServices(IPluginOutInventoryService service) {
+ logger.trace("Got a service UNset request");
+ if (this.pluginOutInventoryServices != null) {
+ this.pluginOutInventoryServices.remove(service);
+ }
+ }
/**
* Function called by the dependency manager when all the required
void start() {
}
+ /**
+ * Method called when the plugin has exposed it's services, this will be
+ * used to publish the updates so connection manager can think the
+ * connection is local
+ */
+ void started() {
+ // update sal and discovery
+ for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+ for (Node node : nodeProps.keySet()) {
+ Set<Property> props = new HashSet<Property>(nodeProps.get(node)
+ .values());
+ service.updateNode(node, UpdateType.ADDED, props);
+ logger.trace("Adding Node {} with props {}", node, props);
+ }
+ for (NodeConnector nc : nodeConnectorProps.keySet()) {
+ Set<Property> props = new HashSet<Property>(nodeConnectorProps.get(nc)
+ .values());
+ service.updateNodeConnector(nc, UpdateType.ADDED, props);
+ logger.trace("Adding NodeConnectors {} with props {}", nc, props);
+ }
+ }
+ }
+
/**
* Function called by the dependency manager before the services exported by
* the component are unregistered, this will be followed by a "destroy ()"
*
*/
void stop() {
+ pluginOutInventoryServices.clear();
}
/**
/**
* Check whether the current match conflicts with the passed filter match
* This match conflicts with the filter if for at least a MatchType defined
- * in the filter match, the respective MatchFields differ or are not compatible
+ * in the filter match, the respective MatchFields differ or are not
+ * compatible
+ *
+ * In other words the function returns true if the set of packets described
+ * by one match and the set of packets described by the other match are
+ * disjoint. Equivalently, if the intersection of the two sets of packets
+ * described by the two matches is an empty.
*
* For example, Let's suppose the filter has the following MatchFields:
* DL_TYPE = 0x800
- * NW_DST = 172.20.30.110/24
+ * NW_DST = 172.20.30.110/24
*
* while this match has the following MatchFields:
+ * DL_TYPE = 0x800
* NW_DST = 172.20.30.45/24
* TP_DST = 80
*
- * Then the function would return false as the two Match are not conflicting
+ * Then the function would return false as the two Match are not
+ * conflicting.
*
- * Note: the mask value is taken into account only for MatchType.NW_SRC and MatchType.NW_DST
+ * Note: the mask value is taken into account only for MatchType.NW_SRC and
+ * MatchType.NW_DST
*
- * @param match the MAtch describing the filter
- * @return true if the match is conflicting with the filter, false otherwise
+ * @param match
+ * the Match describing the filter
+ * @return true if the set of packets described by one match and the set of
+ * packets described by the other match are disjoint, false
+ * otherwise
*/
public boolean conflictWithFilter(Match filter) {
- // Iterate through the MatchType defined in the filter
- for (MatchType type : filter.getMatchesList()) {
+ return !this.intersetcs(filter);
+ }
+
+ /**
+ * Merge the current Match fields with the fields of the filter Match. A
+ * check is first run to see if this Match is compatible with the filter
+ * Match. If it is not, the merge is not attempted.
+ *
+ * The result is the match object representing the intersection of the set
+ * of packets described by this match with the set of packets described by
+ * the filter match. If the intersection of the two sets is empty, the
+ * return match will be null.
+ *
+ * @param filter
+ * the match with which attempting the merge
+ * @return a new Match object describing the set of packets represented by
+ * the intersection of this and the filter matches. null if the
+ * intersection is empty.
+ */
+ public Match mergeWithFilter(Match filter) {
+ return this.getIntersection(filter);
+ }
+
+ /**
+ * Return the match representing the intersection of the set of packets
+ * described by this match with the set of packets described by the other
+ * match. Such as m.getIntersection(m) == m, m.getIntersection(u) == m and
+ * m.getIntersection(o) == o where u is an empty match (universal set, all
+ * packets) and o is the null match (empty set).
+ *
+ * @param other
+ * the match with which computing the intersection
+ * @return a new Match object representing the intersection of the set of
+ * packets described by this match with the set of packets described
+ * by the other match. null when the intersection is the empty set.
+ */
+ public Match getIntersection(Match other) {
+ // If no intersection, return the empty set
+ if (!this.intersetcs(other)) {
+ return null;
+ }
+ // Check if any of the two is the universal match
+ if (this.getMatches() == 0) {
+ return other.clone();
+ }
+ if (other.getMatches() == 0) {
+ return this.clone();
+ }
+ // Derive the intersection
+ Match intersection = new Match();
+ for (MatchType type : MatchType.values()) {
+ if (this.isAny(type) && other.isAny(type)) {
+ continue;
+ }
if (this.isAny(type)) {
+ intersection.setField(other.getField(type).clone());
+ continue;
+ } else if (other.isAny(type)) {
+ intersection.setField(this.getField(type).clone());
+ continue;
+ }
+ // Either they are equal or it is about IP address
+ switch (type) {
+ // When it is about IP address, take the wider prefix address
+ // between the twos
+ case NW_SRC:
+ case NW_DST:
+ MatchField thisField = this.getField(type);
+ MatchField otherField = other.getField(type);
+ InetAddress thisAddress = (InetAddress) thisField.getValue();
+ InetAddress otherAddress = (InetAddress) otherField.getValue();
+ InetAddress thisMask = (InetAddress) thisField.getMask();
+ InetAddress otherMask = (InetAddress) otherField.getMask();
+
+ int thisMaskLen = (thisMask == null) ? ((thisAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+ .getSubnetMaskLength(thisMask);
+ int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+ .getSubnetMaskLength(otherMask);
+ if (otherMaskLen < thisMaskLen) {
+ intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(otherAddress, otherMaskLen),
+ otherMask));
+ } else {
+ intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(thisAddress, thisMaskLen),
+ thisMask));
+ }
+ break;
+ default:
+ // this and other match field are equal for this type, pick this
+ // match field
+ intersection.setField(this.getField(type).clone());
+ }
+ }
+ return intersection;
+ }
+
+ /**
+ * Checks whether the intersection of the set of packets described by this
+ * match with the set of packets described by the other match is non empty
+ *
+ * For example, if this match is: DL_SRC = 00:cc:bb:aa:11:22
+ *
+ * and the other match is: DL_TYPE = 0x800 NW_SRC = 1.2.3.4
+ *
+ * then their respective matching packets set intersection is non empty:
+ * DL_SRC = 00:cc:bb:aa:11:22 DL_TYPE = 0x800 NW_SRC = 1.2.3.4
+ *
+ * @param other
+ * the other match with which testing the intersection
+ * @return true if the intersection of the respective matching packets sets
+ * is non empty
+ */
+ public boolean intersetcs(Match other) {
+ // No intersection with the empty set
+ if (other == null) {
+ return false;
+ }
+ // Always intersection with the universal set
+ if (this.getMatches() == 0 || other.getMatches() == 0) {
+ return true;
+ }
+ // Iterate through the MatchType defined in the filter
+ for (MatchType type : MatchType.values()) {
+ if (this.isAny(type) || other.isAny(type)) {
continue;
}
MatchField thisField = this.getField(type);
- MatchField filterField = filter.getField(type);
+ MatchField otherField = other.getField(type);
switch (type) {
case DL_SRC:
case DL_DST:
- if (Arrays.equals((byte[]) thisField.getValue(),
- (byte[]) filterField.getValue())) {
+ if (!Arrays.equals((byte[]) thisField.getValue(), (byte[]) otherField.getValue())) {
return false;
}
break;
case NW_SRC:
case NW_DST:
InetAddress thisAddress = (InetAddress) thisField.getValue();
- InetAddress filterAddress = (InetAddress) filterField
- .getValue();
+ InetAddress otherAddress = (InetAddress) otherField.getValue();
// Validity check
- if (thisAddress instanceof Inet4Address
- && filterAddress instanceof Inet6Address
- || thisAddress instanceof Inet6Address
- && filterAddress instanceof Inet4Address) {
- return true;
+ if (thisAddress instanceof Inet4Address && otherAddress instanceof Inet6Address
+ || thisAddress instanceof Inet6Address && otherAddress instanceof Inet4Address) {
+ return false;
}
InetAddress thisMask = (InetAddress) thisField.getMask();
- InetAddress filterMask = (InetAddress) filterField.getMask();
- // thisAddress has to be in same subnet of filterAddress
- if (NetUtils.inetAddressConflict(thisAddress, filterAddress,
- thisMask, filterMask)) {
- return true;
+ InetAddress otherMask = (InetAddress) otherField.getMask();
+ if (NetUtils.inetAddressConflict(thisAddress, otherAddress, thisMask, otherMask)
+ && NetUtils.inetAddressConflict(otherAddress, thisAddress, otherMask, thisMask)) {
+ return false;
}
break;
default:
- if (!thisField.getValue().equals(filterField.getValue())) {
- return true;
- }
- }
- //TODO: check v4 v6 incompatibility
- }
- return false;
- }
-
- /**
- * Merge the current Match fields with the fields of the filter Match
- * A check is first run to see if this Match is compatible with the
- * filter Match. If it is not, the merge is not attempted.
- *
- *
- * @param filter
- * @return
- */
- public Match mergeWithFilter(Match filter) {
- if (!this.conflictWithFilter(filter)) {
- /*
- * No conflict with the filter
- * We can copy over the fields which this match does not have
- */
- for (MatchType type : filter.getMatchesList()) {
- if (this.isAny(type)) {
- this.setField(filter.getField(type).clone());
+ if (!thisField.getValue().equals(otherField.getValue())) {
+ return false;
}
}
}
- return this;
+ return true;
}
@Override
@Override
public String toString() {
- return type + "(" + getValueString() + "," + getMaskString() + ")";
+ return (mask == null) ? String.format("%s(%s)", getTypeString(), getValueString()) :
+ String.format("%s(%s,%s)", getTypeString(), getValueString(), getMaskString());
}
@Override
* Checks if the test address and mask conflicts with the filter address and
* mask
*
- * For example: testAddress: 172.28.2.23 testMask: 255.255.255.0
- * filtAddress: 172.28.1.10 testMask: 255.255.255.0 conflict
+ * For example:
+ * testAddress: 172.28.2.23
+ * testMask: 255.255.255.0
+ * filterAddress: 172.28.1.10
+ * testMask: 255.255.255.0
+ * do conflict
*
- * testAddress: 172.28.2.23 testMask: 255.255.255.0 filtAddress: 172.28.1.10
- * testMask: 255.255.0.0 do not conflict
+ * testAddress: 172.28.2.23
+ * testMask: 255.255.255.0
+ * filterAddress: 172.28.1.10
+ * testMask: 255.255.0.0
+ * do not conflict
*
* Null parameters are permitted
*
int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
.getSubnetMaskLength(testMask);
- int filterMaskLen = NetUtils.getSubnetMaskLength(filterMask);
+ int filterMaskLen = (filterMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+ .getSubnetMaskLength(filterMask);
// Mask length check. Test mask has to be more specific than filter one
if (testMaskLen < filterMaskLen) {
/*
* Following utilities are useful when you need to compare or bit shift java
- * primitive type variable which are inerently signed
+ * primitive type variable which are inherently signed
*/
/**
* Returns the unsigned value of the passed byte variable
Assert.assertTrue(field.getValue().equals(new Short(vlan)));
Assert.assertTrue(field.isValid());
}
+
+ @Test
+ public void testIntersection() throws UnknownHostException {
+ Short ethType = Short.valueOf((short)0x800);
+ InetAddress ip1 = InetAddress.getByName("1.1.1.1");
+ InetAddress ip2 = InetAddress.getByName("1.1.1.0");
+ InetAddress ipm2 = InetAddress.getByName("255.255.255.0");
+ InetAddress ip3 = InetAddress.getByName("1.3.0.0");
+ InetAddress ipm3 = InetAddress.getByName("255.255.0.0");
+
+ Match m1 = new Match();
+ m1.setField(MatchType.DL_TYPE, ethType);
+ m1.setField(MatchType.NW_SRC, ip1);
+
+ Match m2 = new Match();
+ m2.setField(MatchType.DL_TYPE, ethType);
+ m2.setField(MatchType.NW_SRC, ip2, ipm2);
+
+ Match m3 = new Match();
+ m3.setField(MatchType.DL_TYPE, ethType);
+ m3.setField(MatchType.NW_SRC, ip3, ipm3);
+ m3.setField(MatchType.NW_PROTO, IPProtocols.TCP.byteValue());
+
+ Match m3r = m3.reverse();
+ Assert.assertTrue(m3.intersetcs(m3r));
+
+ Assert.assertTrue(m1.intersetcs(m2));
+ Assert.assertTrue(m2.intersetcs(m1));
+ Assert.assertFalse(m1.intersetcs(m3));
+ Assert.assertTrue(m1.intersetcs(m3r));
+ Assert.assertFalse(m3.intersetcs(m1));
+ Assert.assertTrue(m3.intersetcs(m1.reverse()));
+ Assert.assertFalse(m2.intersetcs(m3));
+ Assert.assertFalse(m3.intersetcs(m2));
+ Assert.assertTrue(m2.intersetcs(m3r));
+
+
+ Match i = m1.getIntersection(m2);
+ Assert.assertTrue(((Short)i.getField(MatchType.DL_TYPE).getValue()).equals(ethType));
+ Assert.assertTrue(((InetAddress)i.getField(MatchType.NW_SRC).getValue()).equals(ip2));
+ Assert.assertTrue(((InetAddress)i.getField(MatchType.NW_SRC).getMask()).equals(ipm2));
+
+ // Empty set
+ i = m2.getIntersection(m3);
+ Assert.assertNull(i);
+
+ Match m4 = new Match();
+ m4.setField(MatchType.DL_TYPE, ethType);
+ m4.setField(MatchType.NW_PROTO, IPProtocols.TCP.byteValue());
+ Assert.assertTrue(m4.intersetcs(m3));
+
+ Match m5 = new Match();
+ m5.setField(MatchType.DL_TYPE, ethType);
+ m3.setField(MatchType.NW_SRC, ip3, ipm3);
+ m5.setField(MatchType.NW_PROTO, IPProtocols.UDP.byteValue());
+ Assert.assertFalse(m5.intersetcs(m3));
+ Assert.assertFalse(m5.intersetcs(m4));
+ Assert.assertTrue(m5.intersetcs(m5));
+ Assert.assertFalse(m3.intersetcs(m5));
+ Assert.assertFalse(m4.intersetcs(m5));
+
+
+ Match i2 = m4.getIntersection(m3);
+ Assert.assertFalse(i2.getMatches() == 0);
+ Assert.assertFalse(i2.getMatchesList().isEmpty());
+ Assert.assertTrue(((InetAddress)i2.getField(MatchType.NW_SRC).getValue()).equals(ip3));
+ Assert.assertTrue(((InetAddress)i2.getField(MatchType.NW_SRC).getMask()).equals(ipm3));
+ Assert.assertTrue(((Byte)i2.getField(MatchType.NW_PROTO).getValue()).equals(IPProtocols.TCP.byteValue()));
+
+ byte src[] = {(byte)0, (byte)0xab,(byte)0xbc,(byte)0xcd,(byte)0xde,(byte)0xef};
+ byte dst[] = {(byte)0x10, (byte)0x11,(byte)0x12,(byte)0x13,(byte)0x14,(byte)0x15};
+ Short srcPort = (short)1024;
+ Short dstPort = (short)80;
+
+ // Check identity
+ Match m6 = new Match();
+ m6.setField(MatchType.DL_SRC, src);
+ m6.setField(MatchType.DL_DST, dst);
+ m6.setField(MatchType.NW_SRC, ip2, ipm2);
+ m6.setField(MatchType.NW_DST, ip3, ipm3);
+ m6.setField(MatchType.NW_PROTO, IPProtocols.UDP.byteValue());
+ m6.setField(MatchType.TP_SRC, srcPort);
+ m6.setField(MatchType.TP_DST, dstPort);
+ Assert.assertTrue(m6.intersetcs(m6));
+ Assert.assertTrue(m6.getIntersection(m6).equals(m6));
+
+ // Empty match, represents the universal set (all packets)
+ Match u = new Match();
+ Assert.assertTrue(m6.getIntersection(u).equals(m6));
+ Assert.assertTrue(u.getIntersection(m6).equals(m6));
+
+ // No intersection with null match, empty set
+ Assert.assertNull(m6.getIntersection(null));
+ }
}
@RequestMapping(value = "/nodeports")
@ResponseBody
- public Map<String, Object> getNodePorts(HttpServletRequest request,
+ public List<NodeJsonBean> getNodePorts(HttpServletRequest request,
@RequestParam(required = false) String container) {
String containerName = (container == null) ? GlobalConstants.DEFAULT
.toString() : container;
return null;
}
-
ISwitchManager switchManager = (ISwitchManager) ServiceHelper
.getInstance(ISwitchManager.class, containerName, this);
if (switchManager == null) {
return null;
}
-
- Map<String, Object> nodes = new HashMap<String, Object>();
- Map<Short, String> port;
+ List<NodeJsonBean> nodeJsonBeans = new ArrayList<NodeJsonBean>();
for (Switch node : switchManager.getNetworkDevices()) {
- port = new HashMap<Short, String>(); // new port
+ NodeJsonBean nodeJsonBean = new NodeJsonBean();
+ List<String> port = new ArrayList<String>();
Set<NodeConnector> nodeConnectorSet = node.getNodeConnectors();
if (nodeConnectorSet != null) {
String nodeConnectorName = ((Name) switchManager
.getNodeConnectorProp(nodeConnector,
Name.NamePropName)).getValue();
- port.put((Short) nodeConnector.getID(), nodeConnectorName
+ port.add(nodeConnectorName
+ "(" + nodeConnector.getID() + ")");
}
}
-
- nodes.put(node.getNode().toString(), port);
+ nodeJsonBean.setNodeId(node.getNode().toString());
+ nodeJsonBean.setNodeName(getNodeDesc(node.getNode().toString(), containerName));
+ nodeJsonBean.setNodePorts(port);
+ nodeJsonBeans.add(nodeJsonBean);
}
- return nodes;
+ return nodeJsonBeans;
}
@RequestMapping(value = "/spanPorts/add", method = RequestMethod.GET)
--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.devices.web;
+
+import java.util.List;
+
+public class NodeJsonBean {
+ String nodeId;
+ String nodeName;
+ List<String> nodePorts;
+
+ public String getNodeId() {
+ return nodeId;
+ }
+
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ public List<String> getNodePorts() {
+ return nodePorts;
+ }
+
+ public void setNodeId(String nodeId) {
+ this.nodeId = nodeId;
+ }
+
+ public void setNodeName(String nodeName) {
+ this.nodeName = nodeName;
+ }
+
+ public void setNodePorts(List<String> port) {
+ this.nodePorts = port;
+ }
+
+}
// bind onchange
$select.change(function() {
// retrieve port value
- var node = $(this).find('option:selected').attr('value');
- one.f.switchmanager.spanPortConfig.registry['currentNode'] = node;
+ var nodeId = $(this).find('option:selected').attr('value');
+ one.f.switchmanager.spanPortConfig.registry['currentNode'] = nodeId;
var $ports = $('#' + one.f.switchmanager.spanPortConfig.id.modal.form.port);
- var ports = nodeports[node];
- one.lib.form.select.inject($ports, ports);
+ var ports = one.f.switchmanager.spanPortConfig.registry['nodePorts'][nodeId]
+ one.lib.form.select.inject($ports, ports);
});
$fieldset.append($label).append($select);
ajax: {
nodes: function(callback) {
$.getJSON(one.f.switchmanager.rootUrl + "/nodeports", function(data) {
- var nodes = one.f.switchmanager.spanPortConfig.modal.data.nodes(data);
- var nodeports = data;
- one.f.switchmanager.spanPortConfig.registry['nodeports'] = nodeports;
- callback(nodes, nodeports);
+ var nodes = {};
+ var nodePorts = {};
+ $(data).each(function(index, node) {
+ nodes[node.nodeId] = node.nodeName;
+ nodePorts[node.nodeId] = node.nodePorts;
+ });
+ one.f.switchmanager.spanPortConfig.registry['nodePorts'] = nodePorts;
+ callback(nodes, nodePorts);
});
},
saveSpanPortConfig: function(requestData, callback) {
});
}
},
- data : {
- nodes : function(data) {
- result = {};
- $.each(data, function(key, value) {
- result[key] = key;
- });
- return result;
- }
- },
footer : function() {
var footer = [];
var saveButton = one.lib.dashlet.button.single("Save", one.f.switchmanager.spanPortConfig.id.modal.save, "btn-success", "");