*/
@Override
public Object[] getGlobalImplementations() {
- Object[] res = { ClusterManager.class, ClusterGlobalManager.class };
+ Object[] res = { ClusterManager.class, ClusterGlobalManager.class, ClusterManagerCLI.class };
return res;
}
--- /dev/null
+package org.opendaylight.controller.clustering.services_implementation.internal;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.felix.service.command.Descriptor;
+import org.infinispan.AdvancedCache;
+import org.infinispan.distribution.DistributionManager;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.osgi.framework.ServiceRegistration;
+
+public class ClusterManagerCLI {
+ @SuppressWarnings("rawtypes")
+ private ServiceRegistration sr = null;
+
+ public void init() {
+ }
+
+ public void destroy() {
+ }
+
+ public void start() {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put("osgi.command.scope", "odpcontroller");
+ props.put("osgi.command.function", new String[] { "getContainerAdvancedCacheInfo" });
+ this.sr = ServiceHelper.registerGlobalServiceWReg(ClusterManagerCLI.class, this, props);
+ }
+
+ public void stop() {
+ if (this.sr != null) {
+ this.sr.unregister();
+ this.sr = null;
+ }
+ }
+
+ @Descriptor("Get advanced cache infos")
+ public void getContainerAdvancedCacheInfo(@Descriptor("Container for the cache to be fetched") String container,
+ @Descriptor("cache to get information about") String cacheName) {
+ IClusterContainerServices s =
+ (IClusterContainerServices) ServiceHelper.getInstance(IClusterContainerServices.class, container, this);
+ if (s == null) {
+ System.out.println("Could not get an handle to the container cluster service:" + container);
+ return;
+ }
+ if (!s.existCache(cacheName)) {
+ System.out.println("Could not get cache named:" + cacheName);
+ }
+ ConcurrentMap<?, ?> aC = s.getCache(cacheName);
+ if (aC == null) {
+ System.out.println("Could not get cache named:" + cacheName);
+ return;
+ }
+ if (aC instanceof AdvancedCache) {
+ @SuppressWarnings("rawtypes")
+ AdvancedCache advCache = (AdvancedCache) aC;
+ System.out.println("AdvancedCache retrieved!");
+ DistributionManager dMgr = advCache.getDistributionManager();
+ if (dMgr == null) {
+ return;
+ }
+ System.out.println("Routing Table for the Hash:" + dMgr.getConsistentHash()
+ .getRoutingTableAsString());
+ System.out.println("Get Members:" + dMgr.getConsistentHash()
+ .getMembers());
+ }
+ }
+}
org.opendaylight.controller.sal.core,
org.apache.felix.dm
</Import-Package>
+ <Export-Package>
+ org.opendaylight.controller.clustering.test.internal
+ </Export-Package>
<Bundle-Activator>
org.opendaylight.controller.clustering.test.internal.Activator
</Bundle-Activator>
containerName, cacheName);
if (c != null) {
ci.println("\nAdd mapping " + key + " = " + sValue);
- c.put(key, new StringContainer(sValue));
+ try {
+ c.put(key, new StringContainer(sValue));
+ } catch (Exception e) {
+ ci.println("Exception raised:" + e);
+ ci.println("\tStacktrace:");
+ e.printStackTrace();
+ }
} else {
ci.println("Cache " + cacheName + " on container " + containerName
+ " not existant!");
}
/**
- * Returns the protocol
+ * Get the IP protocol value
*
* @return the protocol
*/
public Short getProtoNum() {
- return protocol == null ? IPProtocols.ANY.shortValue() : IPProtocols.getProtocolNumberShort(protocol);
+ return protocol == null ? null : IPProtocols.getProtocolNumberShort(protocol);
}
/**
/**
* Validate the protocol field. Either it can be a enum defined in IPProtocols.java
- * or a value between 1 and 255
+ * or a valid IP proto value between 0 and 255, see:
+ * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+ * for more details.
*
* @return true if a valid protocol value
*/
private boolean hasValidProtocol() {
- if (protocol != null && !protocol.isEmpty()) {
- short proto = this.getProtoNum();
- return (((proto != 0) && (proto > 0) && (proto < 256)) || protocol.equalsIgnoreCase("any"));
- }
- return true;
+ IPProtocols p = IPProtocols.fromString(protocol);
+ return p != null;
}
/**
mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
match.setField(MatchType.NW_DST, ip, mask);
}
- if (this.protocol != null && !this.protocol.trim().isEmpty() && !this.protocol.equalsIgnoreCase("any")) {
- match.setField(MatchType.NW_PROTO, IPProtocols
- .getProtocolNumberByte(this.protocol));
+ if (IPProtocols.fromString(this.protocol) != IPProtocols.ANY) {
+ match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
}
if (this.tpSrc != null && !this.tpSrc.trim().isEmpty()) {
match.setField(MatchType.TP_SRC, Integer.valueOf(tpSrc).shortValue());
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.Collections;
-import java.util.Date;
import java.util.Dictionary;
import java.util.EnumSet;
import java.util.HashSet;
return staticRouteConfigs;
}
- public void setStaticRouteConfigs(
- ConcurrentMap<String, StaticRouteConfig> staticRouteConfigs) {
- this.staticRouteConfigs = staticRouteConfigs;
- }
-
@Override
public Object readObject(ObjectInputStream ois)
throws FileNotFoundException, IOException, ClassNotFoundException {
}
private class NotifyStaticRouteWorker implements Callable<Object> {
+
+ private String name;
private StaticRoute staticRoute;
private boolean added;
- public NotifyStaticRouteWorker(StaticRoute s, boolean update) {
+ public NotifyStaticRouteWorker(String name, StaticRoute s, boolean update) {
+ this.name = name;
this.staticRoute = s;
this.added = update;
}
if (host != null) {
log.debug("Next hop {} is found", nh.getHostAddress());
staticRoute.setHost(host);
+ // static route object has changed
+ // put the changed object back in the cache
+ // for it to sync
+ staticRoutes.put(name, staticRoute);
notifyStaticRouteUpdate(staticRoute, added);
} else {
log.debug("Next hop {} is still not present, try again later", nh.getHostAddress());
}
}
- private void checkAndUpdateListeners(StaticRoute staticRoute, boolean added) {
- NotifyStaticRouteWorker worker = new NotifyStaticRouteWorker(staticRoute, added);
+ private void checkAndUpdateListeners(String name, StaticRoute staticRoute, boolean added) {
+ NotifyStaticRouteWorker worker = new NotifyStaticRouteWorker(name, staticRoute, added);
try {
executor.submit(worker);
} catch (Exception e) {
if (host == null) {
return;
}
- for (StaticRoute s : staticRoutes.values()) {
- if (s.getType() == StaticRoute.NextHopType.SWITCHPORT) {
+ for (Map.Entry<String, StaticRoute> s : staticRoutes.entrySet()) {
+ StaticRoute route = s.getValue();
+ if (route.getType() == StaticRoute.NextHopType.SWITCHPORT) {
continue;
}
- if (s.getNextHopAddress().equals(host.getNetworkAddress())) {
+ if (route.getNextHopAddress().equals(host.getNetworkAddress())) {
if (added) {
- s.setHost(host);
+ route.setHost(host);
} else {
- s.setHost(null);
+ route.setHost(null);
}
- notifyStaticRouteUpdate(s, added);
+ // static route object has changed
+ // put the changed object back in the cache
+ // for it to sync
+ staticRoutes.put(s.getKey(), route);
+ notifyStaticRouteUpdate(route, added);
}
}
}
staticRouteConfigs.put(config.getName(), config);
// Notify
- checkAndUpdateListeners(sRoute, true);
+ checkAndUpdateListeners(config.getName(), sRoute, true);
return status;
}
staticRouteConfigs.remove(name);
StaticRoute sRoute = staticRoutes.remove(name);
if (sRoute != null) {
- checkAndUpdateListeners(sRoute, false);
+ checkAndUpdateListeners(name, sRoute, false);
return new Status(StatusCode.SUCCESS, null);
}
return new Status(StatusCode.NOTFOUND,
gatewayProbeTimer.schedule(new TimerTask() {
@Override
public void run() {
- for (StaticRoute s : staticRoutes.values()) {
- if ((s.getType() == StaticRoute.NextHopType.IPADDRESS)
- && s.getHost() == null) {
- checkAndUpdateListeners(s, true);
+ for (Map.Entry<String, StaticRoute> s : staticRoutes.entrySet()) {
+ StaticRoute route = s.getValue();
+ if ((route.getType() == StaticRoute.NextHopType.IPADDRESS)
+ && route.getHost() == null) {
+ checkAndUpdateListeners(s.getKey(), route, true);
}
}
}
}
public boolean isProtocolValid(String protocol) {
- int protocol_number = IPProtocols.getProtocolNumberInt(protocol);
- if (protocol_number < 1 || protocol_number > 255) {
- return false;
- }
- return true;
+ IPProtocols proto = IPProtocols.fromString(protocol);
+ return (proto != null);
}
private Status conflictWithContainerFlow(IContainer container) {
mask = NetUtils.getInetNetworkMask(maskLen, ip instanceof Inet6Address);
match.setField(MatchType.NW_DST, ip, mask);
}
- if (this.protocol != null) {
+ if (IPProtocols.fromString(this.protocol) != IPProtocols.ANY) {
match.setField(MatchType.NW_PROTO, IPProtocols.getProtocolNumberByte(this.protocol));
}
if (this.tosBits != null) {
private ConcurrentMap<FlowEntryDistributionOrder, FlowEntryDistributionOrderFutureTask> workMonitor =
new ConcurrentHashMap<FlowEntryDistributionOrder, FlowEntryDistributionOrderFutureTask>();
- /*
- * Create an executor pool to create the distributionOrder, this is a stop
- * gap solution caused by an issue with non-transactional caches in the
- * implementation we use, being currently worked on. It has been noticed in
- * fact that when non-transactional caches are being used sometime the key
- * are no distributed to all the nodes properly. To workaround the issue
- * transactional caches are being used, but there was a reason for using
- * non-transactional caches to start with, in fact we needed to be able in
- * the context of a northbound transaction to program the FRM entries
- * irrespective of the fact that transaction would commit or no else we
- * would not be able to achieve the entry programming and implement the
- * scheme for recovery from network element failures. Bottom line, now in
- * order to make sure an update on a transactional cache goes out while in a
- * transaction that need to be initiated by a different thread.
- */
- private ExecutorService executor;
-
- class DistributeOrderCallable implements Callable<Future<Status>> {
- private FlowEntryInstall e;
- private FlowEntryInstall u;
- private UpdateType t;
- DistributeOrderCallable(FlowEntryInstall e, FlowEntryInstall u, UpdateType t) {
- this.e = e;
- this.u = u;
- this.t = t;
- }
-
- @Override
- public Future<Status> call() throws Exception {
- if (e == null || t == null) {
- logsync.error("Unexpected null Entry up update type");
- return null;
- }
- // Create the work order and distribute it
- FlowEntryDistributionOrder fe =
- new FlowEntryDistributionOrder(e, t, clusterContainerService.getMyAddress());
- // First create the monitor job
- FlowEntryDistributionOrderFutureTask ret = new FlowEntryDistributionOrderFutureTask(fe);
- logsync.trace("Node {} not local so sending fe {}", e.getNode(), fe);
- workMonitor.put(fe, ret);
- if (t.equals(UpdateType.CHANGED)) {
- // Then distribute the work
- workOrder.put(fe, u);
- } else {
- // Then distribute the work
- workOrder.put(fe, e);
- }
- logsync.trace("WorkOrder requested");
- // Now create an Handle to monitor the execution of the operation
- return ret;
- }
- }
-
/**
* @param e
* Entry being installed/updated/removed
Node n = e.getNode();
if (connectionManager.getLocalityStatus(n) == ConnectionLocality.NOT_LOCAL) {
- Callable<Future<Status>> worker = new DistributeOrderCallable(e, u, t);
- if (worker != null) {
- Future<Future<Status>> workerRes = this.executor.submit(worker);
- try {
- return workerRes.get();
- } catch (InterruptedException e1) {
- // we where interrupted, not a big deal.
- return null;
- } catch (ExecutionException e1) {
- logsync.error(
- "We got an execution exception {} we cannot much, so returning we don't have nothing to wait for",
- e);
- return null;
- }
+ // Create the work order and distribute it
+ FlowEntryDistributionOrder fe =
+ new FlowEntryDistributionOrder(e, t, clusterContainerService.getMyAddress());
+ // First create the monitor job
+ FlowEntryDistributionOrderFutureTask ret = new FlowEntryDistributionOrderFutureTask(fe);
+ logsync.trace("Node {} not local so sending fe {}", n, fe);
+ workMonitor.put(fe, ret);
+ if (t.equals(UpdateType.CHANGED)) {
+ // Then distribute the work
+ workOrder.put(fe, u);
+ } else {
+ // Then distribute the work
+ workOrder.put(fe, e);
}
+ logsync.trace("WorkOrder requested");
+ // Now create an Handle to monitor the execution of the operation
+ return ret;
}
logsync.trace("Node {} could be local. so processing Entry:{} UpdateType:{}", n, e, t);
EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
clusterContainerService.createCache(WORKSTATUSCACHE,
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
clusterContainerService.createCache(WORKORDERCACHE,
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
+ EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
} catch (CacheConfigException cce) {
log.error("CacheConfigException");
* pratice to have in it's context operations that can take time,
* hence moving off to a different thread for async processing.
*/
+ private ExecutorService executor;
@Override
public void modeChangeNotify(final Node node, final boolean proactive) {
Callable<Status> modeChangeCallable = new Callable<Status>() {
} else {
log.warn("Not expected null WorkStatus", work);
}
+ } else if (event instanceof ContainerFlowChangeEvent) {
+ /*
+ * Whether it is an addition or removal, we have to
+ * recompute the merged flows entries taking into
+ * account all the current container flows because
+ * flow merging is not an injective function
+ */
+ updateFlowsContainerFlow();
} else {
log.warn("Dequeued unknown event {}", event.getClass()
.getSimpleName());
}
log.trace("Container {}: Updating installed flows because of container flow change: {} {}",
container.getName(), t, current);
- /*
- * Whether it is an addition or removal, we have to recompute the merged
- * flows entries taking into account all the current container flows
- * because flow merging is not an injective function
- */
- updateFlowsContainerFlow();
+ ContainerFlowChangeEvent ev = new ContainerFlowChangeEvent(previous, current, t);
+ pendingEvents.offer(ev);
}
@Override
return newEntry;
}
}
+ private class ContainerFlowChangeEvent extends FRMEvent {
+ private final ContainerFlow previous;
+ private final ContainerFlow current;
+ private final UpdateType type;
+
+ public ContainerFlowChangeEvent(ContainerFlow previous, ContainerFlow current, UpdateType type) {
+ this.previous = previous;
+ this.current = current;
+ this.type = type;
+ }
+
+ public ContainerFlow getPrevious() {
+ return this.previous;
+ }
+
+ public ContainerFlow getCurrent() {
+ return this.current;
+ }
+
+ public UpdateType getType() {
+ return this.type;
+ }
+ }
+
private class WorkStatusCleanup extends FRMEvent {
private FlowEntryDistributionOrder fe;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
-import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBElement;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
import org.codehaus.enunciate.jaxrs.TypeHint;
+import org.opendaylight.controller.containermanager.ContainerConfig;
+import org.opendaylight.controller.containermanager.ContainerFlowConfig;
import org.opendaylight.controller.containermanager.IContainerAuthorization;
+import org.opendaylight.controller.containermanager.IContainerManager;
import org.opendaylight.controller.northbound.commons.RestMessages;
import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.usermanager.IUserManager;
-import org.opendaylight.controller.containermanager.ContainerFlowConfig;
-import org.opendaylight.controller.containermanager.IContainerManager;
-import org.opendaylight.controller.containermanager.ContainerConfig;
-
/**
* Container Manager Northbound API
*
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/containers
*
- * Response Payload in XML:
+ * Response body in XML:
* <container-config-list>
*    <container-config>
*       <container>black</container>
*     </container-config>
* </container-config-list>
*
- * Response Payload in JSON:
- * { "container-config" : [ { "container" : "black", "nodeConnectors" : ["OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21"], "staticVlan" : "10", "flowSpecs : [{ "name": "udp", "protocol": "UDP" }] } ] }
- * { "container-config" : [ { "container" : "red", "nodeConnectors" : ["OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21"], "staticVlan" : "20", "flowSpecs": [{ "name": "tcp", "protocol": "TCP" }] } ] }
- *
+ * Response body in JSON:
+ * { "container-config" : [
+ * { "container" : "black",
+ * "nodeConnectors" : [
+ * "OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21"
+ * ],
+ * "staticVlan" : "10",
+ * "flowSpecs : [
+ * { "name": "udp",
+ * "protocol": "UDP" }
+ * ]
+ * },
+ * { "container" : "red",
+ * "nodeConnectors" : [
+ * "OF|1@OF|00:00:00:00:00:00:00:01",
+ * "OF|23@OF|00:00:00:00:00:00:20:21"
+ * ],
+ * "staticVlan" : "20",
+ * "flowSpecs": [
+ * { "name": "tcp",
+ * "protocol": "TCP"
+ * }
+ * ]
+ * }
+ * ]
+ * }
* </pre>
*/
@Path("/containers")
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/blue
*
- * Response Payload in XML:
+ * Response body in XML:
* <container-config>
*     <container>blue</container>
*     <staticVlan>10</staticVlan>
*     <nodeConnectors>OF|23@OF|00:00:00:00:00:00:20:21</nodeConnectors>
* </container-config>
*
- * Response Payload in JSON:
- * { "container" : "blue", "nodeConnectors" : ["OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21"], "staticVlan" : "10" }
- *
+ * Response body in JSON:
+ * {
+ * "container-config": [
+ * {
+ * "container": "yellow",
+ * "staticVlan": "10",
+ * "nodeConnectors": [
+ * "OF|1@OF|00:00:00:00:00:00:00:01",
+ * "OF|2@OF|00:00:00:00:00:00:00:02"
+ * ],
+ * "flowSpecs": []
+ * }
+ * ]
+ * }
* </pre>
*/
@Path("/container/{container}")
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/yellow
*
- * Request Payload in XML:
+ * Request body in XML:
* <container-config>
*     <container>yellow</container>
*     <staticVlan>10</staticVlan>
*     <nodeConnectors></nodeConnectors>
* </container-config>
*
- * Request Payload in JSON:
- * { "container" : "yellow", "nodeConnectors" : ["OF|1@OF|00:00:00:00:00:00:00:01", "OF|23@OF|00:00:00:00:00:00:20:21"], "staticVlan" : "10"}
+ * Request body in JSON:
+ * {
+ * "container" : "yellow",
+ * "nodeConnectors" : [
+ * "OF|1@OF|00:00:00:00:00:00:00:01",
+ * "OF|23@OF|00:00:00:00:00:00:20:21"
+ * ],
+ * "staticVlan" : "10"
+ * }
*
* </pre>
*/
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/green/flowspec/ssh
*
- * Response Payload in XML:
- * <container-flowconfig>
+ * Response body in XML:
+ * <flow-spec-config>
*     <name>ssh</name>
*     <nwSrc>10.0.0.101</nwSrc>
*     <nwDst>10.0.0.102</nwDst>
*     <protocol>IPv4</protocol>
*     <tpSrc>80</tpSrc>
*     <tpDst>100</tpDst>
- * </container-flowconfig>
- *
- * Response Payload in JSON:
- * { "protocol" : "IPv4", "nwDst" : "10.0.0.102", "name" : "ssh", "nwSrc" : "10.0.0.101", "tpSrc" : "80", "tpDst" : "100" }
+ * </flow-spec-config>
+ *
+ * Response body in JSON:
+ * {
+ * "protocol" : "IPv4",
+ * "nwDst" : "10.0.0.102",
+ * "name" : "ssh",
+ * "nwSrc" : "10.0.0.101",
+ * "tpSrc" : "80",
+ * "tpDst" : "100"
+ * }
*
* </pre>
*/
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/red/flowspec
*
- * Response Payload in XML:
- * <container-flowconfigs>
- *     <container-flowconfig>
+ * Response body in XML:
+ * <flow-spec-configs>
+ *     <flow-spec-config>
*       <name>ssh</name>
*       <nwSrc>10.0.0.101</nwSrc>
*       <nwDst>10.0.0.102</nwDst>
*       <protocol>IPv4</protocol>
*       <tpSrc>23</tpSrc>
*       <tpDst>100</tpDst>
- *     </container-flowconfig>
- *     <container-flowconfig>
+ *     </flow-spec-config>
+ *     <flow-spec-config>
*       <name>http2</name>
*       <nwSrc>10.0.0.201</nwSrc>
*       <nwDst>10.0.0.202</nwDst>
*       <protocol></protocol>
*       <tpSrc>80</tpSrc>
*       <tpDst>100</tpDst>
- *     </container-flowconfig>
- * </container-flowconfigs>
- *
- * Response Payload in JSON:
- * { "protocol" : "IPv4", "nwDst" : "10.0.0.102", "name" : "ssh" , "nwSrc" : "10.0.0.101", "tpSrc" : "23", "tpDst" : "100" }
- * { "protocol" : "", "nwDst" : "10.0.0.202", "name" : "http" , "nwSrc" : "10.0.0.201", "tpSrc" : "80", "tpDst" : "100" }
+ *     </flow-spec-config>
+ * </flow-spec-configs>
+ *
+ * Response body in JSON:
+ * {
+ * "flow-spec-config": [
+ * {
+ * "name": "http",
+ * "nwSrc": "10.0.0.201",
+ * "nwDst": "10.0.0.202",
+ * "protocol": "",
+ * "tpSrc": "80",
+ * "tpDst": "100"
+ * },
+ * {
+ * "name": "ssh",
+ * "nwSrc": "10.0.0.101",
+ * "nwDst": "10.0.0.102",
+ * "protocol": "IPv4",
+ * "tpSrc": "23",
+ * "tpDst": "100"
+ * }
+ * ]
+ * }
*
* </pre>
*/
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/purple/flowspec/http
*
- * Request Payload in XML:
- * <container-flowconfig>
+ * Request body in XML:
+ * <flow-spec-config>
*     <name>http</name>
*     <nwSrc>10.0.0.101</nwSrc>
*     <nwDst>10.0.0.102</nwDst>
*     <protocol></protocol>
*     <tpSrc>80</tpSrc>
*     <tpDst>100</tpDst>
- * </container-flowconfig>
- *
- * Request Payload in JSON:
- * { "protocol" : "", "nwDst" : "10.0.0.102", "name" : "http", "nwSrc" : "10.0.0.101", "tpSrc" : "80", "tpDst" : "100" }
+ * </flow-spec-config>
+ *
+ * Request body in JSON:
+ * {
+ * "protocol" : "",
+ * "nwDst" : "10.0.0.102",
+ * "name" : "http",
+ * "nwSrc" : "10.0.0.101",
+ * "tpSrc" : "80",
+ * "tpDst" : "100"
+ * }
*
* </pre>
*/
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/green/nodeconnector
*
- * Request Payload in XML:
- * <list>
+ * Request body in XML:
+ * <nodeConnectors>
* <nodeConnectors>OF|1@OF|00:00:00:00:00:00:00:01</nodeConnectors>
* <nodeConnectors>OF|2@OF|00:00:00:00:00:00:00:01</nodeConnectors>
* <nodeConnectors>OF|3@OF|00:00:00:00:00:00:00:22</nodeConnectors>
* <nodeConnectors>OF|4@OF|00:00:00:00:00:00:00:22</nodeConnectors>
- * </list>
- *
- * Request Payload in JSON:
- * { "nodeConnectors" : ["OF|1@OF|00:00:00:00:00:00:00:01", "OF|2@OF|00:00:00:00:00:00:00:01", "OF|3@OF|00:00:00:00:00:00:00:22", "OF|4@OF|00:00:00:00:00:00:00:22" }
+ * </nodeConnectors>
+ *
+ * Request body in JSON:
+ * {
+ * "nodeConnectors" : [
+ * "OF|1@OF|00:00:00:00:00:00:00:01",
+ * "OF|2@OF|00:00:00:00:00:00:00:01",
+ * "OF|3@OF|00:00:00:00:00:00:00:22",
+ * "OF|4@OF|00:00:00:00:00:00:00:22"
+ * ]
+ * }
*
* </pre>
*/
* Request URL:
* http://localhost:8080/controller/nb/v2/containermanager/container/red/nodeconnector
*
- * Request Payload in XML:
- * <list>
+ * Request body in XML:
+ * <nodeConnectors>
* <nodeConnectors>OF|1@OF|00:00:00:00:00:00:00:01</nodeConnectors>
* <nodeConnectors>OF|2@OF|00:00:00:00:00:00:00:01</nodeConnectors>
* <nodeConnectors>OF|3@OF|00:00:00:00:00:00:00:22</nodeConnectors>
* <nodeConnectors>OF|4@OF|00:00:00:00:00:00:00:22</nodeConnectors>
- * </list>
- *
- * Request Payload in JSON:
- * { "nodeConnectors" : ["OF|1@OF|00:00:00:00:00:00:00:01", "OF|2@OF|00:00:00:00:00:00:00:01", "OF|3@OF|00:00:00:00:00:00:00:22", "OF|4@OF|00:00:00:00:00:00:00:22" }
+ * </nodeConnectors>
+ *
+ * Request body in JSON:
+ * {
+ * "nodeConnectors" : [
+ * "OF|1@OF|00:00:00:00:00:00:00:01",
+ * "OF|2@OF|00:00:00:00:00:00:00:01",
+ * "OF|3@OF|00:00:00:00:00:00:00:22",
+ * "OF|4@OF|00:00:00:00:00:00:00:22"
+ * ]
+ * }
*
* </pre>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/flowprogrammer/default
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
*    <flowConfig>
*    </flowConfig>
* </list>
*
- * Response in JSON:
- * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
- * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
- *
+ * Response body in JSON:
+ * {
+ * "flowConfig": [
+ * {
+ * "installInHw": "true",
+ * "name": "flow1",
+ * "node": {
+ * "type": "OF",
+ * "id": "00:00:00:00:00:00:00:01"
+ * },
+ * "ingressPort": "1",
+ * "priority": "500",
+ * "etherType": "0x800",
+ * "nwSrc":"9.9.1.1",
+ * "actions": [
+ * "OUTPUT=2"
+ * ]
+ * }
+ * ]
+ * }
* </pre>
*/
@Path("/{containerName}")
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
*    <flowConfig>
*    </flowConfig>
* </list>
*
- * Response in JSON:
- * {"flowConfig":{"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
- * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}}
- *
+ * Response body in JSON:
+ * {
+ * "flowConfig": [
+ * {
+ * "installInHw": "true",
+ * "name": "flow1",
+ * "node": {
+ * "type": "OF",
+ * "id": "00:00:00:00:00:00:00:01"
+ * },
+ * "ingressPort": "1",
+ * "priority": "500",
+ * "etherType": "0x800",
+ * "nwSrc":"9.9.1.1",
+ * "actions": [
+ * "OUTPUT=2"
+ * ]
+ * }
+ * ]
+ * }
* </pre>
*/
@Path("/{containerName}/node/{nodeType}/{nodeId}")
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <flowConfig>
*    <installInHw>true</installInHw>
*    <actions>OUTPUT=2</actions>
* </flowConfig>
*
- * Response in JSON:
- * {"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
- * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
+ * Response body in JSON:
+ * {
+ * "installInHw":"true",
+ * "name":"flow1",
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "ingressPort":"1",
+ * "priority":"500",
+ * "etherType":"0x800",
+ * "nwSrc":"9.9.1.1",
+ * "actions":[
+ * "OUTPUT=2"
+ * ]
+ * }
*
* </pre>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/flowprogrammer/default/node/OF/00:00:00:00:00:00:00:01/staticFlow/flow1
*
- * Request in XML:
+ * Request body in XML:
* <flowConfig>
*    <installInHw>true</installInHw>
*    <name>flow1</name>
*    <actions>OUTPUT=2</actions>
* </flowConfig>
*
- * Request in JSON:
- * {"installInHw":"true","name":"flow1","node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},
- * "ingressPort":"1","priority":"500","etherType":"0x800","nwSrc":"9.9.1.1","actions":"OUTPUT=2"}
- *
+ * Request body in JSON:
+ * {
+ * "installInHw":"true",
+ * "name":"flow1",
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "ingressPort":"1",
+ * "priority":"500",
+ * "etherType":"0x800",
+ * "nwSrc":"9.9.1.1",
+ * "actions":[
+ * "OUTPUT=2"
+ * ]
+ * }
* </pre>
*/
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBElement;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
*
* Example:
*
- * RequestURL:
- *
+ * Request URL:
* http://localhost:8080/controller/nb/v2/hosttracker/default/hosts/active
*
- * Response in XML
+ * Response body in XML
*
* <list>
*  <hostConfig>
*  </hostConfig>
* </list>
*
- * Response in JSON:
+ * Response body in JSON:
*
* {
*  "hostConfig":[
*
* Example:
*
- * RequestURL:
- *
+ * Request URL:
* http://localhost:8080/controller/nb/v2/hosttracker/default/hosts/inactive
*
- * Response in XML
+ * Response body in XML
*
* <list>
*  <hostConfig>
*  </hostConfig>
* </list>
*
- * Response in JSON:
+ * Response body in JSON:
*
* {
*  "hostConfig":[
*
* Example:
*
- * RequestURL:
- *
+ * Request URL:
* http://localhost:8080/controller/nb/v2/hosttracker/default/address/1.1.1.1
*
- * Response in XML
+ * Response body in XML
*
* <hostConfig>
*  <dataLayerAddress>00:00:00:00:01:01</dataLayerAddress>
*  <staticHost>false</staticHost>
* </hostConfig>
*
- * Response in JSON:
+ * Response body in JSON:
*
* {
*  "dataLayerAddress":"00:00:00:00:01:01",
*
* Example:
*
- * RequestURL:
- *
+ * Request URL:
* http://localhost:8080/controller/nb/v2/hosttracker/default/address/1.1.1.1
*
- * Request in XML
+ * Request body in XML
*
* <hostConfig>
*  <dataLayerAddress>00:00:00:00:01:01</dataLayerAddress>
*  <staticHost>false</staticHost>
* </hostConfig>
*
- * Request in JSON:
+ * Request body in JSON:
*
* {
*  "dataLayerAddress":"00:00:00:00:01:01",
* @param networkAddress
* IP Address
* @return Response as dictated by the HTTP Response code.
+ *
+ * Example:
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/hosttracker/default/address/1.1.1.1
+ *
*/
@Path("/{containerName}/address/{networkAddress}")
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
-import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
-import javax.xml.bind.JAXBElement;
import org.codehaus.enunciate.jaxrs.ResponseCode;
import org.codehaus.enunciate.jaxrs.StatusCodes;
* HTTP/1.1 200 OK
* Content-Type: application/json
*
- * {"staticRoute":{"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}}
+ * { "staticRoute":[
+ * "name":"route-1",
+ * "prefix":"10.10.1.0/24",
+ * "nextHop":"1.1.1.1"
+ * ]
+ * }
*
* </pre>
*
* Example:
*
* Request URL:
- * GET http://localhost:8080/controller/nb/v2/staticroute/default/routes
+ * http://localhost:8080/controller/nb/v2/staticroute/default/routes
*
- * Response in XML:
+ * Response body in XML:
* <list>
* <staticRoute>
* <name>route-1</name>
* </staticRoute>
* </list>
*
- * Response in JSON:
- * {"staticRoute":{"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}}
- *
+ * Response body in JSON:
+ * {
+ * "staticRoute": [
+ * {
+ * "name": "route-1",
+ * "prefix": "10.10.1.0/24",
+ * "nextHop": "1.1.1.1"
+ * }
+ * ]
+ * }
* </pre>
*/
@Path("/{containerName}/routes")
* Example:
*
* Request URL:
- * GET http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
+ * http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
*
- * Response in XML:
+ * Response body in XML:
*
* <staticRoute>
* <name>route-1</name>
* <nextHop>1.1.1.1</nextHop>
* </staticRoute>
*
- * Response in JSON:
- * {"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}
+ * Response body in JSON:
+ * {
+ * "name":"route-1",
+ * "prefix":"10.10.1.0/24",
+ * "nextHop":"1.1.1.1"
+ * }
*
* </pre>
*/
* Example:
*
* Request URL:
- * PUT http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
- *
- * Request payload in JSON:
- * {"name":"route-1","prefix":"10.10.1.0/24","nextHop":"1.1.1.1"}
+ * http://localhost:8080/controller/nb/v2/staticroute/default/route/route-1
*
+ * Request body in XML:
+ * <staticRoute>
+ * <name>route-1</name>
+ * <prefix>10.10.1.0/24</prefix>
+ * <nextHop>1.1.1.1</nextHop>
+ * </staticRoute>
+ * Request body in JSON:
+ * {
+ * "name":"route-1",
+ * "prefix":"10.10.1.0/24",
+ * "nextHop":"1.1.1.1"
+ * }
* </pre>
*/
@Path("/{containerName}/route/{route}")
* Request URL:
* http://localhost:8080/controller/nb/v2/statistics/default/flow
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "flowStatistics": [
* {
* ]
* }
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
* <flowStatistics>
* Request URL:
* http://localhost:8080/controller/nb/v2/statistics/default/flow/node/OF/00:00:00:00:00:00:00:01
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "node": {
* "id":"00:00:00:00:00:00:00:01",
* ]
* }
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <nodeFlowStatistics>
* <node>
* Request URL:
* http://localhost:8080/controller/nb/v2/statistics/default/port
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "portStatistics": [
* {
* ]
* }
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
* <portStatistics>
* Request URL:
* http://localhost:8080/controller/nb/v2/statistics/default/port/node/OF/00:00:00:00:00:00:00:01
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "node": {
* "id":"00:00:00:00:00:00:00:01",
* ]
* }
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <nodePortStatistics>
* <node>
* Request URL:
* http://localhost:8080/controller/nb/v2/statistics/default/table
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "tableStatistics": [
* {
* ]
* }
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
* <tableStatistics>
* Request URL:
* http://localhost:8080/controller/nb/v2/statistics/default/table/node/OF/00:00:00:00:00:00:00:01
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "node": {
* "id":"00:00:00:00:00:00:00:01",
* ]
* }
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <nodeTableStatistics>
* <node>
*
* @return a List of SubnetConfig
*
- * <pre>
+ * <pre>
* Example:
*
- * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnets
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/subnetservice/default/subnets
*
- * Response in XML:
+ * Response body in XML:
+ * <list>
* <subnetConfig>
* <name>marketingdepartment</name>
* <subnet>30.31.54.254/24</subnet>
* <subnetConfig>
* <name>salesdepartment</name>
* <subnet>20.18.1.254/16</subnet>
- * <nodeConnectors>0F|11@OF|00:00:00:aa:bb:cc:dd:ee>/nodeConnectors>
- * <nodeConnectors>0F|13@OF|00:00:00:aa:bb:cc:dd:ee>/nodeConnectors>
+ * <nodeConnectors>OF|11@OF|00:00:00:aa:bb:cc:dd:ee</nodeConnectors>
+ * <nodeConnectors>OF|13@OF|00:00:00:aa:bb:cc:dd:ee</nodeConnectors>
* </subnetConfig>
- *
- * Response in JSON:
+ * </list>
+ * Response body in JSON:
* {
- * "name":"marketingdepartment",
- * "subnet":"30.31.54.254/24",
- * }
- * {
- * "name":"salesdepartment",
- * "subnet":"20.18.1.254/16",
- * "nodeConnectors":["0F|11@OF|00:00:00:aa:bb:cc:dd:ee", "0F|13@OF|00:00:00:aa:bb:cc:dd:ee"]
+ * "subnetConfig": [
+ * {
+ * "name": "marketingdepartment",
+ * "subnet": "30.31.54.254/24",
+ * "nodeConnectors": [
+ * "OF|04@OF|00:00:00:00:00:00:00:04",
+ * "OF|07@OF|00:00:00:00:00:00:00:07"
+ * ]
+ * },
+ * {
+ * "name":"salesdepartment",
+ * "subnet":"20.18.1.254/16",
+ * "nodeConnectors": [
+ * "OF|11@OF|00:00:00:aa:bb:cc:dd:ee",
+ * "OF|13@OF|00:00:00:aa:bb:cc:dd:ee"
+ * ]
+ * }
+ * ]
* }
+ *
* </pre>
*/
@Path("/{containerName}/subnets")
* <pre>
* Example:
*
- * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/marketingdepartment
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/marketingdepartment
*
- * Response in XML:
+ * Response body in XML:
* <subnetConfig>
* <name>marketingdepartment</name>
* <subnet>30.0.0.1/24</subnet>
- * <nodeConnectors>0F|1@OF|00:00:11:22:33:44:55:66>/nodePorts>
- * <nodeConnectors>0F|3@OF|00:00:11:22:33:44:55:66>/nodePorts>
+ * <nodeConnectors>OF|1@OF|00:00:00:00:00:00:00:01</nodePorts>
+ * <nodeConnectors>OF|3@OF|00:00:00:00:00:00:00:03</nodePorts>
* </subnetConfig>
*
- * Response in JSON:
+ * Response body in JSON:
* {
* "name":"marketingdepartment",
* "subnet":"30.0.0.1/24",
- * "nodeConnectors":["0F|1@OF|00:00:11:22:33:44:55:66", "0F|3@OF|00:00:11:22:33:44:55:66"]
+ * "nodeConnectors":[
+ * "OF|1@OF|00:00:00:00:00:00:00:01",
+ * "OF|3@OF|00:00:00:00:00:00:00:03"
+ * ]
* }
* </pre>
*/
* <pre>
* Example:
*
- * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
*
- * Request XML:
+ * Request body in XML:
* <subnetConfig>
* <name>salesdepartment</name>
* <subnet>172.173.174.254/24</subnet>
- * <nodeConnectors>0F|22@OF|00:00:11:22:33:44:55:66>/nodeConnectors>
- * <nodeConnectors>0F|39@OF|00:00:ab:cd:33:44:55:66>/nodeConnectors>
+ * <nodeConnectors>OF|22@OF|00:00:11:22:33:44:55:66</nodeConnectors>
+ * <nodeConnectors>OF|39@OF|00:00:ab:cd:33:44:55:66</nodeConnectors>
* </subnetConfig>
*
- * Request in JSON:
+ * Request body in JSON:
* {
* "name":"salesdepartment",
- * "subnet":"172.173.174.254/24"
- * "nodeConnectors":["0F|22@OF|00:00:11:22:33:44:55:66", "0F|39@OF|00:00:ab:cd:33:44:55:66"]
+ * "subnet":"172.173.174.254/24",
+ * "nodeConnectors":[
+ * "OF|22@OF|00:00:11:22:33:44:55:66",
+ * "OF|39@OF|00:00:ab:cd:33:44:55:66"
+ * ]
* }
* </pre>
*/
* name of new subnet to be deleted
* @return Response as dictated by the HTTP Response Status code
*
- * <pre>
+ * <pre>
* Example:
- * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/engdepartment
+ *
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/engdepartment
*
* </pre>
*/
* <pre>
* Example:
*
- * Request URL: http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
+ * Request URL:
+ * http://localhost:8080/controller/nb/v2/subnetservice/default/subnet/salesdepartment
*
- * Request in XML:
+ * Request body in XML:
* <subnetConfig>
* <name>salesdepartment</name>
* <subnet>172.173.174.254/24</subnet>
- * <nodeConnectors>0F|22@OF|00:00:11:22:33:44:55:66>/nodeConnectors>
- * <nodeConnectors>0F|39@OF|00:00:ab:cd:33:44:55:66>/nodeConnectors>
+ * <nodeConnectors>OF|22@OF|00:00:11:22:33:44:55:66</nodeConnectors>
+ * <nodeConnectors>OF|39@OF|00:00:ab:cd:33:44:55:66</nodeConnectors>
* </subnetConfig>
*
- * Request in JSON:
+ * Request body in JSON:
* {
* "name":"salesdepartment",
- * "subnet":"172.173.174.254/24"
- * "nodeConnectors":["0F|22@OF|00:00:11:22:33:44:55:66", "0F|39@OF|00:00:ab:cd:33:44:55:66"]
+ * "subnet":"172.173.174.254/24",
+ * "nodeConnectors":[
+ * "OF|22@OF|00:00:11:22:33:44:55:66",
+ * "OF|39@OF|00:00:ab:cd:33:44:55:66"
+ * ]
* }
* </pre>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/nodes
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
*    <nodeProperties>
*    </nodeProperties>
* </list>
*
- * Response in JSON:
- * {"nodeProperties":[{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},"properties":{"tables":{"value":"-1"},
- * "description":{"value":"None"},"actions":{"value":"4095"},"macAddress":{"value":"00:00:00:00:00:02"},"capabilities"
- * :{"value":"199"},"timeStamp":{"value":"1377291227877","name":"connectedSince"},"buffers":{"value":"256"}}}]}
+ * Response body in JSON:
+ * {
+ * "nodeProperties":[
+ * {
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "properties":{
+ * "tables":{
+ * "value":"-1"
+ * },
+ * "description":{
+ * "value":"None"
+ * },
+ * "actions":{
+ * "value":"4095"
+ * },
+ * "macAddress":{
+ * "value":"00:00:00:00:00:02"
+ * },
+ * "capabilities":{
+ * "value":"199"
+ * },
+ * "timeStamp":{
+ * "value":"1377291227877",
+ * "name":"connectedSince"
+ * },
+ * "buffers":{
+ * "value":"256"
+ * }
+ * }
+ * }
+ * ]
+ * }
*
* </pre>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:03/property/description/Switch3
*
* </pre>
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:03/property/forwarding
*
* </pre>
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/node/OF/00:00:00:00:00:00:00:01
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <list>
*    <nodeConnectorProperties>
*    </nodeConnectorProperties>
* </list>
*
- * Response in JSON:
- * {"nodeConnectorProperties":[{"nodeconnector":{"node":{"id":"00:00:00:00:00:00:00:01","type":"OF"},"id":"2","type":"OF"},
- * "properties":{"state":{"value":"1"},"config":{"value":"1"},"name":{"value":"L1_2-C2_1"}}}]}
+ * Response body in JSON:
+ * {
+ * "nodeConnectorProperties":[
+ * {
+ * "nodeconnector":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:01",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * },
+ * "properties":{
+ * "state":{
+ * "value":"1"
+ * },
+ * "config":{
+ * "value":"1"
+ * },
+ * "name":{
+ * "value":"L1_2-C2_1"
+ * }
+ * }
+ * }
+ * ]
+ * }
*
* </pre>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth/1
*
* </pre>
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/nodeconnector/OF/00:00:00:00:00:00:00:01/OF/2/property/bandwidth
*
* </pre>
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/switchmanager/default/save
*
* </pre>
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/topology/default
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
* <topology>
* <edgeProperties>
* </edgeProperties>
* </topology>
*
- * Response in JSON:
- * {"edgeProperties":[{"edge":{"tailNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},
- * "id":"2","type":"OF"},"headNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:51","type":"OF"},"id":
- * "2","type":"OF"}},"properties":{"timeStamp":{"value":"1377278961017","name":"creation"}}},
- * {"edge":{"tailNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:51","type":"OF"},"id":
- * "2","type":"OF"}},"headNodeConnector":{"node":{"id":"00:00:00:00:00:00:00:02","type":"OF"},
- * "id":"2","type":"OF"}},"properties":{"timeStamp":{"value":"1377278961018","name":"creation"}}}]}
- *
+ * Response body in JSON:
+ * {
+ * "edgeProperties":[
+ * {
+ * "edge":{
+ * "tailNodeConnector":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * },
+ * "headNodeConnector":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:51",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * }
+ * },
+ * "properties":{
+ * "timeStamp": {
+ * "value": 1379527162648,
+ * "name": "creation",
+ * },
+ * "name": {
+ * "value": "s2-eth3"
+ * },
+ * "state": {
+ * "value": 1
+ * },
+ * "config": {
+ * "value": 1
+ * },
+ * "bandwidth": {
+ * "value": 10000000000
+ * }
+ * }
+ * },
+ * {
+ * "edge":{
+ * "tailNodeConnector":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:51",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * },
+ * "headNodeConnector":{
+ * "node":{
+ * "id":"00:00:00:00:00:00:00:02",
+ * "type":"OF"
+ * },
+ * "id":"2",
+ * "type":"OF"
+ * }
+ * },
+ * "properties":{
+ * "timeStamp": {
+ * "value": 1379527162648,
+ * "name": "creation",
+ * }
+ * }
+ * }
+ * ]
+ * }
* </pre>
*/
@Path("/{containerName}")
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/topology/default/userLinks
*
- * Response in XML:
+ * Response body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- * <topologyUserLinks>
+ * <list>
* <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>
+ * </list>
*
- * 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"}}
+ * Response body in JSON:
+ * {
+ * "userLinks": [
+ * {
+ * "status": "Success",
+ * "name": "link1",
+ * "srcNodeConnector": "OF|2@OF|00:00:00:00:00:00:00:02",
+ * "dstNodeConnector": "OF|5@OF|00:00:00:00:00:00:00:05"
+ * }
+ * ]
+ * }
*
* </pre>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/topology/default/userLink/link1
*
- * Request in XML:
+ * Request body in XML:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- * <topologyUserLinks>
+ * <topologyUserLinkConfig>
* <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>
+ * </topologyUserLinkConfig>
*
- * 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"}
+ * Request body 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>
*/
*
* Example:
*
- * RequestURL:
+ * Request URL:
* http://localhost:8080/controller/nb/v2/topology/default/userLink/config1
*
* </pre>
byte tos = (byte) (dscp >> 2);
salMatch.setField(MatchType.NW_TOS, tos);
}
+ //TODO: NW protocol 0 is a valid protocol
if (ofMatch.getNetworkProtocol() != 0) {
salMatch.setField(MatchType.NW_PROTO,
ofMatch.getNetworkProtocol());
package org.opendaylight.controller.sal.match;
import java.io.Serializable;
+
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
private Object value; // the value of the field we want to match
private Object mask; // the value of the mask we want to match on the
// specified field
- private transient boolean isValid;
+ private boolean isValid;
// To satisfy JAXB
@SuppressWarnings("unused")
cloned.mask = ((byte[]) this.mask).clone();
}
}
+ cloned.type = this.type;
+ cloned.isValid = this.isValid;
} catch (CloneNotSupportedException e) {
logger.error("", e);
}
import java.util.List;
/**
- * It represents the most common IP protocols numbers
- * It provides the binding between IP protocol names and numbers
- * and provides APIs to read and parse them in either of the two forms
- *
+ * Enum represents the most common IP protocols numbers It provides the binding
+ * between IP protocol names and numbers and provides APIs to read and parse
+ * them in either of the two forms
*
+ * NOTE: Openflow 1.0 supports the IP Proto match only for ICMP, TCP and UDP
*
+ * references:
+ * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
*/
-// Openflow 1.0 supports the IP Proto match only for ICMP, TCP and UDP
public enum IPProtocols {
- ANY("any", 0),
- /* HOPOPT("HOPOPT",0),
- */ICMP("ICMP", 1),
- /* IGMP("IGMP",2),
+ ANY("any", -1),
+ HOPOPT("HOPOPT",0),
+ ICMP("ICMP", 1),
+ IGMP("IGMP",2),
GGP("GGP",3),
IPV4("IPv4",4),
ST("ST",5),
- */TCP("TCP", 6),
- /* CBT("CBT",7),
+ TCP("TCP", 6),
+ CBT("CBT",7),
EGP("EGP",8),
IGP("IGP",9),
BBNRCCMON("BBN-RCC-MON",10),
EMCON("EMCON",14),
XNET("XNET",15),
CHAOS("CHAOS",16),
- */UDP("UDP", 17),
- /* MUX("MUX",18),
+ UDP("UDP", 17),
+ MUX("MUX",18),
DCNMEAS("DCN-MEAS",19),
HMP("HMP",20),
PRM("PRM",21),
MOBILE("MOBILE",55),
TLSP("TLSP",56),
SKIP("SKIP",57),
- */IPV6ICMP("IPv6-ICMP", 58);
- /* IPV6NoNxt("IPv6-NoNxt",59),
+ IPV6ICMP("IPv6-ICMP", 58),
+ IPV6NoNxt("IPv6-NoNxt",59),
IPV6Opts("IPv6-Opts",60),
ANYHOST("ANY-HOST",61),
CFTP("CFTP",62),
HIP("HIP",139),
SHIM6("Shim6",140),
WESP("WESP",141),
- ROHC("ROHC",142);
- */
- private static final String regexDecimalString = "^[0-9]{3}$";
- private static final String regexHexString = "^(0(x|X))[0-9a-fA-F]{2}$";
+ ROHC("ROHC",142),
+ /*143-252 Unassigned by IANA*/
+
+ //Experimebtal protocol numbers (http://tools.ietf.org/html/rfc3692)
+ EXP1("Experimental1", 253),
+ EXP2("Experimental2", 254),
+
+ RESERVED("RESERVED",255);
+
private String protocolName;
private int protocolNumber;
return ((Integer) protocolNumber).byteValue();
}
+ @Override
public String toString() {
return protocolName;
}
}
public static String getProtocolName(short number) {
- return getProtocolNameInternal((int) number & 0xffff);
+ return getProtocolNameInternal(number & 0xffff);
}
public static String getProtocolName(byte number) {
- return getProtocolNameInternal((int) number & 0xff);
+ return getProtocolNameInternal(number & 0xff);
}
private static String getProtocolNameInternal(int number) {
return proto.toString();
}
}
+ //TODO: this is for backwards compatibility
return "0x" + Integer.toHexString(number);
}
public static short getProtocolNumberShort(String name) {
- if (name.matches(regexHexString)) {
- return Short.valueOf(Short.decode(name));
- }
- if (name.matches(regexDecimalString)) {
- return Short.valueOf(name);
+ IPProtocols p = fromString(name);
+ if (p != null) {
+ return p.shortValue();
}
- for (IPProtocols proto : IPProtocols.values()) {
- if (proto.protocolName.equalsIgnoreCase(name)) {
- return proto.shortValue();
- }
- }
- return 0;
+ //This method should be called after validation only
+ throw new IllegalArgumentException("Illegal IP protocol value: " + name);
}
public static int getProtocolNumberInt(String name) {
- if (name.matches(regexHexString)) {
- return Integer.valueOf(Integer.decode(name));
- }
- if (name.matches(regexDecimalString)) {
- return Integer.valueOf(name);
- }
- for (IPProtocols proto : IPProtocols.values()) {
- if (proto.protocolName.equalsIgnoreCase(name)) {
- return proto.intValue();
- }
+ IPProtocols p = fromString(name);
+ if (p != null) {
+ return p.intValue();
}
- return 0;
+ //This method should be called after validation only
+ throw new IllegalArgumentException("Illegal IP protocol value: " + name);
}
public static byte getProtocolNumberByte(String name) {
- if (name.matches(regexHexString)) {
- return Integer.valueOf(Integer.decode(name)).byteValue();
+ IPProtocols p = fromString(name);
+ if (p != null) {
+ return p.byteValue();
}
- if (name.matches(regexDecimalString)) {
- return Integer.valueOf(name).byteValue();
- }
- for (IPProtocols proto : IPProtocols.values()) {
- if (proto.protocolName.equalsIgnoreCase(name)) {
- return proto.byteValue();
- }
- }
- return 0;
+ //This method should be called after validation only
+ throw new IllegalArgumentException("Illegal IP protocol value: " + name);
}
public static List<String> getProtocolNameList() {
}
return protoList;
}
+
+ /**
+ * Method to parse an IPProtocol from a numeric string
+ * (see: {@link Java.Lang.Integer.decode(java.lang.String)} for parsable strings),
+ * or this enum's name string.
+ *
+ * @param s
+ * The IP protocol string to be parsed
+ * @return The IP protocol Enum, or null if invalid protocol string is passed
+ */
+ public static IPProtocols fromString(String s) {
+ // null/empty/any/* evaluates to ANY
+ if (s == null || s.isEmpty() || s.equalsIgnoreCase("any") || s.equals("*")) {
+ return IPProtocols.ANY;
+ }
+
+ // Try parsing numeric and find the related ENUM
+ try {
+ int protoNum = Integer.decode(s);
+ for (IPProtocols protoEnum : IPProtocols.values()) {
+ if (protoEnum.protocolNumber == protoNum) {
+ return protoEnum;
+ }
+ }
+ // At this point it's an invalid number (i.e. out of range or not a valid proto num)
+ return null;
+ } catch (NumberFormatException nfe) {
+ // numeric failed try by NAME
+ try {
+ return valueOf(s);
+ } catch(IllegalArgumentException e) {
+ // Neither numeric nor enum NAME, attempt human readable name
+ for (IPProtocols protoEnum : IPProtocols.values()) {
+ if (protoEnum.toString().equalsIgnoreCase(s)) {
+ return protoEnum;
+ }
+ }
+ //couldn't parse, signifies an invalid proto field!
+ return null;
+ }
+
+ }
+ }
}
--- /dev/null
+/**
+ *
+ */
+package org.opendaylight.controller.sal.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * @author ykhodork
+ *
+ */
+public class IPProtocolsTest {
+
+ static short shortVal = 1;
+ static int intVal = 1;
+ static byte byteVal = 1;
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolName(int)}.
+ */
+ @Test
+ public void testGetProtocolNameInt() {
+ assertEquals("ICMP", IPProtocols.getProtocolName(1));
+ assertEquals("0x4d2", IPProtocols.getProtocolName(1234));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolName(short)}.
+ */
+ @Test
+ public void testGetProtocolNameShort() {
+ assertEquals("ICMP", IPProtocols.getProtocolName(shortVal));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolName(byte)}.
+ */
+ @Test
+ public void testGetProtocolNameByte() {
+ assertEquals("ICMP", IPProtocols.getProtocolName(byteVal));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolNumberShort(java.lang.String)}.
+ */
+ @Test
+ public void testGetProtocolNumberShort() {
+ assertEquals(shortVal, IPProtocols.getProtocolNumberShort("ICMP"));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolNumberInt(java.lang.String)}.
+ */
+ @Test
+ public void testGetProtocolNumberInt() {
+ assertEquals(intVal, IPProtocols.getProtocolNumberInt("ICMP"));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#getProtocolNumberByte(java.lang.String)}.
+ */
+ @Test
+ public void testGetProtocolNumberByte() {
+ assertEquals(byteVal, IPProtocols.getProtocolNumberByte("ICMP"));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.controller.sal.utils.IPProtocols#fromString(java.lang.String)}.
+ */
+ @Test
+ public void testFromString() {
+ assertTrue(null == IPProtocols.fromString("Not a protocol"));
+ assertTrue(null == IPProtocols.fromString("0xFFF"));
+ assertTrue(null == IPProtocols.fromString("-2"));
+
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString("any"));
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString("ANY"));
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString("*"));
+ assertTrue(IPProtocols.ANY == IPProtocols.fromString(null));
+
+ assertTrue(IPProtocols.TCP == IPProtocols.fromString("TCP"));
+ assertTrue(IPProtocols.TCP == IPProtocols.fromString("tcp"));
+ assertTrue(IPProtocols.UDP == IPProtocols.fromString("0x11"));
+ assertTrue(IPProtocols.UDP == IPProtocols.fromString("0X11"));
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Map<Node, Set<Edge>> nodeEdges = topologyManager.getNodeEdges();
Map<Node, Set<NodeConnector>> hostEdges = topologyManager
.getNodesWithNodeConnectorHost();
+ int hostEdgesHashCode = getHostHashCode(hostEdges, topologyManager);
List<Switch> nodes = switchManager.getNetworkDevices();
List<SwitchConfig> switchConfigurations = new ArrayList<SwitchConfig>();
// return cache if topology hasn't changed
if (
(metaNodeHash.get(containerName) != null && metaHostHash.get(containerName) != null && metaNodeSingleHash.get(containerName) != null && metaNodeConfigurationHash.get(containerName) != null) &&
- metaNodeHash.get(containerName).equals(nodeEdges.hashCode()) && metaHostHash.get(containerName).equals(hostEdges.hashCode()) && metaNodeSingleHash.get(containerName).equals(nodes.hashCode()) && metaNodeConfigurationHash.get(containerName).equals(switchConfigurations.hashCode())
+ metaNodeHash.get(containerName).equals(nodeEdges.hashCode()) && metaHostHash.get(containerName).equals(hostEdgesHashCode) && metaNodeSingleHash.get(containerName).equals(nodes.hashCode()) && metaNodeConfigurationHash.get(containerName).equals(switchConfigurations.hashCode())
) {
return metaCache.get(containerName).values();
}
// cache has changed, we must assign the new values
metaNodeHash.put(containerName, nodeEdges.hashCode());
- metaHostHash.put(containerName, hostEdges.hashCode());
+ metaHostHash.put(containerName, hostEdgesHashCode);
metaNodeSingleHash.put(containerName, nodes.hashCode());
metaNodeConfigurationHash.put(containerName, switchConfigurations.hashCode());
if (edgeIgnore(link)) {
continue;
}
- for (Property p : properties.get(link)) {
+ Set<Property> props = properties.get(link);
+ if (props == null) {
+ continue;
+ }
+ for (Property p : props) {
if (p instanceof Bandwidth) {
bandwidth = (Bandwidth) p;
break;
}
}
+ /**
+ * Calculate the total host hashcode
+ *
+ * This is to handle cases where there are multiple hosts per NodeConnector
+ *
+ * @param hostEdges
+ * - hostEdges data structure
+ * @param topology
+ * - topology bundle
+ * @return this topology's host hashcode
+ */
+ private int getHostHashCode(Map<Node, Set<NodeConnector>> hostEdges, ITopologyManager topology) {
+ List<Host> hosts = new ArrayList<Host>();
+ for (Set<NodeConnector> nodeConnectors : hostEdges.values()) {
+ for (NodeConnector nodeConnector : nodeConnectors) {
+ List<Host> theseHosts = topology.getHostsAttachedToNodeConnector(nodeConnector);
+ hosts.addAll(theseHosts);
+ }
+ }
+
+ return hosts.hashCode();
+ }
+
/**
* Add regular hosts to main topology
*