NetworkConfigManager loads a configuration file and exposes an interface for
querying network configuration. Currently it only supports startup configuration.
Change-Id: I6b67bde56b2c97471470090b26f3e05dc6f1d7c7
diff --git a/conf/example-network.conf b/conf/example-network.conf
new file mode 100644
index 0000000..db9effb
--- /dev/null
+++ b/conf/example-network.conf
@@ -0,0 +1,101 @@
+{
+ "comment": " Multilayer topology description and configuration",
+ "restrictSwitches": false,
+ "restrictLinks": false,
+
+ "switchConfig":
+ [
+ { "nodeDpid": "00:00:ff:ff:ff:ff:ff:00", "name": "Dallas-R1", "type": "Router_SR", "allowed": true,
+ "latitude": 80.80, "longitude": 90.10,
+ "params": { "routerIp": "192.168.10.10/32",
+ "routerMac": "00:ba:ba:00:10:10",
+ "nodeSid": 110,
+ "adjacencySids": [
+ { "portNo": 3, "adjSid": 10234 },
+ { "portNo": 5, "adjSid": 29019 }
+ ],
+ "subnets": [
+ { "portNo": 1, "subnetIp": "10.0.1.1/24" },
+ { "portNo": 4, "subnetIp": "10.0.2.1/24" },
+ { "portNo": 5, "subnetIp": "10.0.3.1/24" }
+ ]
+ }
+ },
+
+ { "nodeDpid": "00:00:ff:ff:ff:ff:ff:01", "name": "Dallas-R2", "type": "Router_SR", "allowed": true,
+ "latitude": 80.80, "longitude": 90.10,
+ "params": { "routerIp": "192.168.10.11/32",
+ "routerMac": "00:ba:ba:00:10:11",
+ "nodeSid": 111,
+ "adjacencySids": [
+ { "portNo": 3, "adjSid": 10234 },
+ { "portNo": 5, "adjSid": 29019 }
+ ],
+ "subnets": [
+ { "portNo": 1, "subnetIp": "10.0.4.1/24" },
+ { "portNo": 4, "subnetIp": "10.0.5.1/24" },
+ { "portNo": 5, "subnetIp": "10.0.6.1/24" }
+ ]
+ }
+ },
+
+ { "nodeDpid": "00:00:ff:ff:ff:ff:ff:02", "name": "Dallas-W1", "type": "Roadm", "allowed": true,
+ "latitude": 80.80, "longitude": 90.10,
+ "params": { "numRegen": 2 }
+ },
+
+ { "nodeDpid": "00:00:ff:ff:ff:ff:ff:03", "name": "NYC-W10", "type": "Roadm", "allowed": true,
+ "latitude": 80.80, "longitude": 90.10,
+ "params": { "numRegen": 3 }
+ },
+
+ { "nodeDpid": "00:00:ff:ff:ff:ff:ff:04", "name": "Dallas-S1", "type": "Switch_OF10", "allowed": true,
+ "latitude": 80.80, "longitude": 90.10
+ }
+
+
+ ],
+
+ "linkConfig":[
+ { "type": "pktLink", "allowed": true,
+ "nodeDpid1": "00:00:ff:ff:ff:ff:ff:00", "nodeDpid2": "00:00:ff:ff:ff:ff:ff:04",
+ "params": { "nodeName1": "Dallas-R1", "port1": 3,
+ "nodeName2": "Dallas-S1", "port2": 20
+ }
+ },
+
+ { "type": "pktLink", "allowed": true,
+ "nodeDpid1": "00:00:ff:ff:ff:ff:ff:00", "nodeDpid2": "00:00:ff:ff:ff:ff:ff:04",
+ "params": { "port1": 4, "port2": 3 }
+ },
+
+ { "type": "wdmLink", "allowed": true,
+ "nodeDpid1": "00:00:ff:ff:ff:ff:ff:02", "nodeDpid2": "00:00:ff:ff:ff:ff:ff:03",
+ "params": { "nodeName1": "Dallas-W1",
+ "nodeName2": "NYC-W10",
+ "distKms": 5000, "numWaves": 80
+ }
+ },
+
+ { "type": "pktOptLink", "allowed": true,
+ "nodeDpid1": "00:00:ff:ff:ff:ff:ff:00", "nodeDpid2": "00:00:ff:ff:ff:ff:ff:02",
+ "params": { "nodeName1": "Dallas-R1", "port1": 33,
+ "nodeName2": "Dallas-W1", "port2": 10
+ }
+ },
+
+ { "type": "pktLink", "allowed": true,
+ "nodeDpid1": "00:00:ff:ff:ff:ff:ff:00", "nodeDpid2": "00:00:ff:ff:ff:ff:ff:01",
+ "params": { "port1": 6, "port2": 1 }
+ }
+
+ ],
+
+ "opticalReachabilty":
+ [
+ [ "Dallas-W1", "NYC-W10" ],
+ [ "NYC-W10", "Dallas-W1" ],
+ [ "Dallas-W2", "SFO-W3" ],
+ [ "SFO-W3", "Dallas-W2" ]
+ ]
+}
diff --git a/conf/onos.properties b/conf/onos.properties
index e2b0bdc..e6d5292 100644
--- a/conf/onos.properties
+++ b/conf/onos.properties
@@ -18,3 +18,5 @@
net.onrc.onos.core.datagrid.HazelcastDatagrid.datagridConfig =
# Uncomment and list all the ZooKeeper instances after localhost on multi-instance deployment.
#net.onrc.onos.core.registry.ZookeeperRegistry.connectionString = localhost:2181,otherhost:2181
+# Specify a network configuration file to be used by the NetworkConfigManager
+#net.onrc.onos.core.configmanager.NetworkConfigManager.networkConfigFile = conf/my_network.conf
diff --git a/src/main/java/net/onrc/onos/core/configmanager/INetworkConfigService.java b/src/main/java/net/onrc/onos/core/configmanager/INetworkConfigService.java
new file mode 100644
index 0000000..4090879
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/INetworkConfigService.java
@@ -0,0 +1,260 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.List;
+
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
+import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
+import net.onrc.onos.core.linkdiscovery.Link;
+import net.onrc.onos.core.util.Dpid;
+
+/**
+ * Exposes methods to retrieve network configuration.
+ * <p>
+ * TODO: currently only startup-configuration is exposed and such configuration
+ * cannot be changed at runtime. Need to add runtime support for changes to
+ * configuration (via REST/CLI) in future releases.
+ * <p>
+ * TODO: return immutable objects or defensive copies of network config so that
+ * users of this API do not inadvertently or maliciously change network config.
+ */
+public interface INetworkConfigService extends IFloodlightService {
+
+ /**
+ * Suggests the action to be taken by the caller given the configuration
+ * associated with the queried network-object (eg. switch, link etc.).
+ */
+ public enum NetworkConfigState {
+ /**
+ * Associated network object has been configured to not be allowed in
+ * the network.
+ */
+ DENY,
+
+ /**
+ * Associated network object has been configured to be allowed in the
+ * network.
+ */
+ ACCEPT,
+
+ /**
+ * Associated network object has been configured to be allowed in the
+ * network. In addition, there are configured parameters that should be
+ * added to the object.
+ */
+ ACCEPT_ADD,
+ }
+
+ /**
+ * Returns the configuration outcome (accept, deny etc.), and any configured
+ * parameters to the caller, in response to a query for the configuration
+ * associated with a switch.
+ */
+ public class SwitchConfigStatus {
+ private NetworkConfigState configState;
+ private SwitchConfig switchConfig;
+ private String msg;
+
+ SwitchConfigStatus(NetworkConfigState configState,
+ SwitchConfig switchConfig, String msg) {
+ this.configState = configState;
+ this.switchConfig = switchConfig;
+ this.msg = msg;
+ }
+
+ SwitchConfigStatus(NetworkConfigState configState,
+ SwitchConfig switchConfig) {
+ this.configState = configState;
+ this.switchConfig = switchConfig;
+ this.msg = "";
+ }
+
+ /**
+ * Returns the configuration state for the switch.
+ *
+ * @return non-null NetworkConfigState
+ */
+ public NetworkConfigState getConfigState() {
+ return configState;
+ }
+
+ /**
+ * Returns the switch configuration, which may be null if no
+ * configuration exists, or if the configuration state disallows the
+ * switch.
+ *
+ * @return SwitchConfig, the switch configuration, or null
+ */
+ public SwitchConfig getSwitchConfig() {
+ return switchConfig;
+ }
+
+ /**
+ * User readable string typically used to specify the reason why a
+ * switch is being disallowed.
+ *
+ * @return A non-null but possibly empty String
+ */
+ public String getMsg() {
+ return msg;
+ }
+
+ }
+
+ /**
+ * Returns the configuration outcome (accept, deny etc.), and any configured
+ * parameters to the caller, in response to a query for the configuration
+ * associated with a link.
+ */
+ public class LinkConfigStatus {
+ private NetworkConfigState configState;
+ private LinkConfig linkConfig;
+ private String msg;
+
+ LinkConfigStatus(NetworkConfigState configState,
+ LinkConfig linkConfig, String msg) {
+ this.configState = configState;
+ this.linkConfig = linkConfig;
+ this.msg = msg;
+ }
+
+ LinkConfigStatus(NetworkConfigState configState,
+ LinkConfig linkConfig) {
+ this.configState = configState;
+ this.linkConfig = linkConfig;
+ this.msg = "";
+ }
+
+ /**
+ * Returns the configuration state for the link.
+ *
+ * @return non-null NetworkConfigState
+ */
+ public NetworkConfigState getConfigState() {
+ return configState;
+ }
+
+ /**
+ * Returns the link configuration, which may be null if no configuration
+ * exists, or if the configuration state disallows the link.
+ *
+ * @return SwitchConfig, the switch configuration, or null
+ */
+ public LinkConfig getLinkConfig() {
+ return linkConfig;
+ }
+
+ /**
+ * User readable string typically used to specify the reason why a link
+ * is being disallowed.
+ *
+ * @return msg A non-null but possibly empty String
+ */
+ public String getMsg() {
+ return msg;
+ }
+
+ }
+
+ /**
+ * Checks the switch configuration (if any) associated with the 'dpid'.
+ * Determines if the switch should be allowed or denied according to
+ * configuration rules.
+ * <p>
+ * The method always returns a non-null SwitchConfigStatus. The enclosed
+ * ConfigState contains the result of the check. The enclosed SwitchConfig
+ * may or may not be null, depending on the outcome of the check.
+ *
+ * @param dpid of the switch to be queried
+ * @return SwitchConfigStatus with outcome of check and associated config.
+ */
+ public SwitchConfigStatus checkSwitchConfig(Dpid dpid);
+
+ /**
+ * Checks the link configuration (if any) associated with the 'link'.
+ * Determines if the link should be allowed or denied according to
+ * configuration rules. Note that the 'link' is a unidirectional link which
+ * checked against configuration that is typically defined for a
+ * bidirectional link. The caller may make a second call if it wishes to
+ * check the 'reverse' direction.
+ * <p>
+ * Also note that the configuration may not specify ports for a given
+ * bidirectional link. In such cases, the configuration applies to all links
+ * between the two switches. This method will check the given 'link' against
+ * such configuration.
+ * <p>
+ * The method always returns a non-null LinkConfigStatus. The enclosed
+ * ConfigState contains the result of the check. The enclosed LinkConfig may
+ * or may not be null, depending on the outcome of the check.
+ *
+ * @param link unidirectional {@link Link} to be queried
+ * @return LinkConfigStatus with outcome of check and associated config.
+ */
+ public LinkConfigStatus checkLinkConfig(Link link);
+
+ /**
+ * Retrieves a list of switches that have been configured, and have been
+ * determined to be 'allowed' in the network, according to configuration
+ * rules.
+ * <p>
+ * Note that it is possible that there are other switches that are allowed
+ * in the network that have NOT been configured. Such switches will not be a
+ * part of the returned list.
+ * <p>
+ * Also note that it is possible that some switches will not be discovered
+ * and the only way the controller can know about these switches is via
+ * configuration. Such switches will be included in this list. It is up to
+ * the caller to determine which SwitchConfig applies to non-discovered
+ * switches.
+ *
+ * @return a non-null List of SwitchConfig which may be empty
+ */
+ public List<SwitchConfig> getConfiguredAllowedSwitches();
+
+ /**
+ * Retrieves a list of links that have been configured, and have been
+ * determined to be 'allowed' in the network, according to configuration
+ * rules.
+ * <p>
+ * Note that it is possible that there are other links that are allowed in
+ * the network that have NOT been configured. Such links will not be a part
+ * of the returned list.
+ * <p>
+ * Also note that it is possible that some links will not be discovered and
+ * the only way the controller can know about these links is via
+ * configuration. Such links will be included in this list. It is up to the
+ * caller to determine which LinkConfig applies to non-discovered links.
+ * <p>
+ * In addition, note that the LinkConfig applies to the configured
+ * bi-directional link, which may or may not have declared ports. The
+ * associated unidirectional LinkTuple can be retrieved from the
+ * getLinkTupleList() method in the LinkConfig object.
+ *
+ * @return a non-null List of LinkConfig which may be empty
+ */
+ public List<LinkConfig> getConfiguredAllowedLinks();
+
+ /**
+ * Retrieves the configured optical (wave) reachability matrix. The String
+ * is the 'name' associated with a configured switch object.
+ * <p>
+ * This method does not check if the switches are 'allowed' by config. TODO:
+ * This method should check if the 'name's in the matrix are valid names
+ * corresponding to configured switches.
+ *
+ * @return a non-null List which may be empty if no reachability matrix has
+ * been configured
+ */
+ public List<List<String>> getOpticalReachabiltyConfig();
+
+ /**
+ * Retrieves the Dpid associated with a 'name' for a configured switch
+ * object. This method does not check of the switches are 'allowed' by
+ * config.
+ *
+ * @return the Dpid corresponding to a given 'name', or null if no
+ * configured switch was found for the given 'name'.
+ */
+ public Dpid getDpidForName(String name);
+
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/NetworkConfig.java b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfig.java
new file mode 100644
index 0000000..9bce826
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfig.java
@@ -0,0 +1,263 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonNode;
+import org.projectfloodlight.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Public class corresponding to JSON described data model. Defines the network
+ * configuration at startup.
+ */
+public class NetworkConfig {
+ protected static final Logger log = LoggerFactory.getLogger(NetworkConfig.class);
+
+ @SuppressWarnings("unused")
+ private String comment;
+
+ private Boolean restrictSwitches;
+ private Boolean restrictLinks;
+ private List<SwitchConfig> switches;
+ private List<LinkConfig> links;
+ private List<List<String>> opticalReachability;
+
+ public NetworkConfig() {
+ switches = new ArrayList<SwitchConfig>();
+ links = new ArrayList<LinkConfig>();
+ opticalReachability = new ArrayList<List<String>>();
+ }
+
+ public void setComment(String c) {
+ comment = c;
+ }
+
+ public void setRestrictSwitches(boolean rs) {
+ restrictSwitches = rs;
+ }
+
+ public Boolean getRestrictSwitches() {
+ return restrictSwitches;
+ }
+
+ public void setRestrictLinks(boolean rl) {
+ restrictLinks = rl;
+ }
+
+ public Boolean getRestrictLinks() {
+ return restrictLinks;
+ }
+
+ // *********************
+ // switches
+ // *********************/
+
+ public List<SwitchConfig> getSwitchConfig() {
+ return switches;
+ }
+
+ public void setSwitchConfig(List<SwitchConfig> switches2) {
+ this.switches = switches2;
+ }
+
+ public static class SwitchConfig {
+ protected String name;
+ protected long dpid;
+ protected String nodeDpid;
+ protected String type;
+ protected double latitude;
+ protected double longitude;
+ protected boolean allowed;
+ protected Map<String, JsonNode> params;
+ protected Map<String, String> publishAttributes;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public long getDpid() {
+ return dpid;
+ }
+
+ public void setDpid(long dpid) {
+ this.dpid = dpid;
+ this.nodeDpid = HexString.toHexString(dpid);
+ }
+
+ public String getNodeDpid() {
+ return nodeDpid;
+ }
+
+ public String getHexDpid() {
+ return nodeDpid;
+ }
+
+ // mapper sets both long and string fields for dpid
+ public void setNodeDpid(String nodeDpid) {
+ this.nodeDpid = nodeDpid;
+ this.dpid = HexString.toLong(nodeDpid);
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public double getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(double latitude) {
+ this.latitude = latitude;
+ }
+
+ public double getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(double longitude) {
+ this.longitude = longitude;
+ }
+
+ public boolean isAllowed() {
+ return allowed;
+ }
+
+ public void setAllowed(boolean allowed) {
+ this.allowed = allowed;
+ }
+
+ public Map<String, JsonNode> getParams() {
+ return params;
+ }
+
+ public void setParams(Map<String, JsonNode> params) {
+ this.params = params;
+ }
+
+ public Map<String, String> getPublishAttributes() {
+ return publishAttributes;
+ }
+
+ public void setPublishAttributes(Map<String, String> publishAttributes) {
+ this.publishAttributes = publishAttributes;
+ }
+
+ }
+
+ // *********************
+ // links
+ // *********************/
+
+ public void setLinkConfig(List<LinkConfig> links2) {
+ this.links = links2;
+ }
+
+ public List<LinkConfig> getLinkConfig() {
+ return links;
+ }
+
+ public static class LinkConfig {
+ protected String type;
+ protected Boolean allowed;
+ protected long dpid1;
+ protected long dpid2;
+ protected String nodeDpid1;
+ protected String nodeDpid2;
+ protected Map<String, JsonNode> params;
+ protected Map<String, String> publishAttributes;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Boolean isAllowed() {
+ return allowed;
+ }
+
+ public void setAllowed(Boolean allowed) {
+ this.allowed = allowed;
+ }
+
+ public String getNodeDpid1() {
+ return nodeDpid1;
+ }
+
+ // mapper sets both long and string fields for dpid
+ public void setNodeDpid1(String nodeDpid1) {
+ this.nodeDpid1 = nodeDpid1;
+ this.dpid1 = HexString.toLong(nodeDpid1);
+ }
+
+ public String getNodeDpid2() {
+ return nodeDpid2;
+ }
+
+ // mapper sets both long and string fields for dpid
+ public void setNodeDpid2(String nodeDpid2) {
+ this.nodeDpid2 = nodeDpid2;
+ this.dpid2 = HexString.toLong(nodeDpid2);
+ }
+
+ public long getDpid1() {
+ return dpid1;
+ }
+
+ public void setDpid1(long dpid1) {
+ this.dpid1 = dpid1;
+ this.nodeDpid1 = HexString.toHexString(dpid1);
+ }
+
+ public long getDpid2() {
+ return dpid2;
+ }
+
+ public void setDpid2(long dpid2) {
+ this.dpid2 = dpid2;
+ this.nodeDpid2 = HexString.toHexString(dpid2);
+ }
+
+ public Map<String, JsonNode> getParams() {
+ return params;
+ }
+
+ public void setParams(Map<String, JsonNode> params) {
+ this.params = params;
+ }
+
+ public Map<String, String> getPublishAttributes() {
+ return publishAttributes;
+ }
+
+ public void setPublishAttributes(Map<String, String> publishAttributes) {
+ this.publishAttributes = publishAttributes;
+ }
+ }
+
+ // *********************
+ // optical reach matrix
+ // *********************/
+
+ public void setOpticalReachabilty(List<List<String>> opticalReach) {
+ this.opticalReachability = opticalReach;
+ }
+ public List<List<String>> getOpticalReachability() {
+ return opticalReachability;
+ }
+
+}
+
diff --git a/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigException.java b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigException.java
new file mode 100644
index 0000000..30cdabd
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigException.java
@@ -0,0 +1,159 @@
+package net.onrc.onos.core.configmanager;
+
+import org.projectfloodlight.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * NetworkConfigExceptions specifies a set of unchecked runtime exceptions that
+ * can be thrown by the {@link NetworkConfigManager}. It indicates errors that
+ * must be fixed in the config file before controller execution can proceed.
+ */
+public class NetworkConfigException extends RuntimeException {
+
+ private static final long serialVersionUID = 4959684709803000652L;
+ protected static final Logger log = LoggerFactory
+ .getLogger(NetworkConfigException.class);
+
+ public static class DuplicateDpid extends RuntimeException {
+ private static final long serialVersionUID = 5491113234592145335L;
+
+ public DuplicateDpid(long dpid) {
+ super();
+ log.error("Duplicate dpid found in switch-config Dpid:{}",
+ HexString.toHexString(dpid));
+ }
+ }
+
+ public static class DuplicateName extends RuntimeException {
+ private static final long serialVersionUID = -4090171438031376129L;
+
+ public DuplicateName(String name) {
+ super();
+ log.error("Duplicate name found in switch-config name:{}", name);
+ }
+ }
+
+ public static class DpidNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = -8494418855597117254L;
+
+ public DpidNotSpecified(String name) {
+ super();
+ log.error("Dpid not specified for switch-config name:{}", name);
+ }
+ }
+
+ public static class NameNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = -3518881744110422891L;
+
+ public NameNotSpecified(long dpid) {
+ super();
+ log.error("Name not specified for switch-config dpid:{}",
+ HexString.toHexString(dpid));
+ }
+ }
+
+ public static class SwitchTypeNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = 2527453336226053753L;
+
+ public SwitchTypeNotSpecified(long dpid) {
+ super();
+ log.error("Switch type not specified for switch-config dpid:{}",
+ HexString.toHexString(dpid));
+ }
+ }
+
+ public static class UnknownSwitchType extends RuntimeException {
+ private static final long serialVersionUID = 7758418165512249170L;
+
+ public UnknownSwitchType(String type, String name) {
+ super();
+ log.error("Unknown switch type {} for switch name:{}", type, name);
+ }
+ }
+
+ public static class ParamsNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = 6247582323691265513L;
+
+ public ParamsNotSpecified(String name) {
+ super();
+ log.error("Params required - not specified for switch:{}", name);
+ }
+ }
+
+ public static class LinkTypeNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = -2089470389588542215L;
+
+ public LinkTypeNotSpecified(String dpid1, String dpid2) {
+ super();
+ log.error("Link type not specified for link-config between "
+ + "dpid1:{} and dpid2:{}", dpid1, dpid2);
+ }
+ }
+
+ public static class LinkDpidNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = -5701825916378616004L;
+
+ public LinkDpidNotSpecified(String dpid1, String dpid2) {
+ super();
+ if (dpid1 == null) {
+ log.error("nodeDpid1 not specified for link-config ");
+ }
+ if (dpid2 == null) {
+ log.error("nodeDpid2 not specified for link-config ");
+ }
+ }
+ }
+
+ public static class LinkForUnknownSwitchConfig extends RuntimeException {
+ private static final long serialVersionUID = -2910458439881964094L;
+
+ public LinkForUnknownSwitchConfig(String dpid) {
+ super();
+ log.error("Link configuration was specified for a switch-dpid {} "
+ + "that has not been configured", dpid);
+ }
+ }
+
+ public static class UnknownLinkType extends RuntimeException {
+ private static final long serialVersionUID = -5505376193106542305L;
+
+ public UnknownLinkType(String linktype, String dpid1, String dpid2) {
+ super();
+ log.error("unknown link type {} for links between dpid1:{} "
+ + "and dpid2:{}", linktype, dpid1, dpid2);
+ }
+ }
+
+ public static class ErrorConfig extends RuntimeException {
+ private static final long serialVersionUID = -2827406314700193147L;
+
+ public ErrorConfig(String errorMsg) {
+ super();
+ log.error(errorMsg);
+ }
+
+ }
+
+ public static class SwitchDpidNotConverted extends RuntimeException {
+ private static final long serialVersionUID = 5640347104590170426L;
+
+ public SwitchDpidNotConverted(String name) {
+ super();
+ log.error("Switch dpid specified as a HexString {} does not match "
+ + "with long value", name);
+ }
+ }
+
+ public static class LinkDpidNotConverted extends RuntimeException {
+ private static final long serialVersionUID = 2397245646094080774L;
+
+ public LinkDpidNotConverted(String dpid1, String dpid2) {
+ log.error("Dpids expressed as HexStrings for links between dpid1:{} "
+ + "and dpid2:{} do not match with long values", dpid1, dpid2);
+ }
+ }
+
+
+}
+
diff --git a/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java
new file mode 100644
index 0000000..0c1f933
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/NetworkConfigManager.java
@@ -0,0 +1,408 @@
+package net.onrc.onos.core.configmanager;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.core.module.FloodlightModuleException;
+import net.floodlightcontroller.core.module.IFloodlightModule;
+import net.floodlightcontroller.core.module.IFloodlightService;
+import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
+import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
+import net.onrc.onos.core.linkdiscovery.Link;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.LinkTuple;
+import net.onrc.onos.core.util.SwitchPort;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.projectfloodlight.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * NetworkConfigManager manages all network configuration for switches, links
+ * and any other state that needs to be configured for correct network
+ * operation.
+ *
+ */
+public class NetworkConfigManager implements IFloodlightModule,
+ INetworkConfigService {
+ protected static final Logger log = LoggerFactory
+ .getLogger(NetworkConfigManager.class);
+ public static final String DEFAULT_NETWORK_CONFIG_FILE =
+ "conf/example-network.conf";
+ /**
+ * JSON Config file needs to use one of the following types for defining the
+ * kind of switch or link it wishes to configure.
+ */
+ private static final String SEGMENT_ROUTER = "Router_SR";
+ private static final String ROADM = "Roadm";
+ private static final String OF10SWITCH = "Switch_OF10";
+
+ private static final String PKT_LINK = "pktLink";
+ private static final String WDM_LINK = "wdmLink";
+ private static final String PKT_OPT_LINK = "pktOptLink";
+
+ NetworkConfig networkConfig;
+ private ConcurrentMap<Long, SwitchConfig> configuredSwitches;
+ private ConcurrentMap<LinkTuple, LinkConfig> configuredLinks;
+ private Map<String, Long> nameToDpid;
+
+ // **************
+ // INetworkConfigService
+ // **************
+
+ public SwitchConfigStatus checkSwitchConfig(Dpid dpid) {
+ SwitchConfig swc = configuredSwitches.get(dpid.value());
+ if (networkConfig.getRestrictSwitches()) {
+ // default deny behavior
+ if (swc == null) {
+ // switch is not configured - we deny this switch
+ return new SwitchConfigStatus(NetworkConfigState.DENY, null,
+ "Switch not configured, in network denying switches by default.");
+ }
+ if (swc.isAllowed()) {
+ // switch is allowed in config, return configured attributes
+ return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
+ } else {
+ // switch has been configured off (administratively down)
+ return new SwitchConfigStatus(NetworkConfigState.DENY, null,
+ "Switch configured down (allowed=false).");
+ }
+ } else {
+ // default allow behavior
+ if (swc == null) {
+ // no config to add
+ return new SwitchConfigStatus(NetworkConfigState.ACCEPT, null);
+ }
+ if (swc.isAllowed()) {
+ // switch is allowed in config, return configured attributes
+ return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
+ } else {
+ // switch has been configured off (administratively down)
+ return new SwitchConfigStatus(NetworkConfigState.DENY, null,
+ "Switch configured down (allowed=false).");
+ }
+ }
+
+ }
+
+ public LinkConfigStatus checkLinkConfig(Link link) {
+ LinkConfig lkc = getConfiguredLink(link);
+ // links are always disallowed if any one of the nodes that make up the
+ // link are disallowed
+ Dpid linkNode1 = new Dpid(link.getSrc());
+ SwitchConfigStatus scs1 = checkSwitchConfig(linkNode1);
+ if (scs1.getConfigState() == NetworkConfigState.DENY) {
+ return new LinkConfigStatus(NetworkConfigState.DENY, null,
+ "Link-node: " + linkNode1 + " denied by config: " + scs1.getMsg());
+ }
+ Dpid linkNode2 = new Dpid(link.getDst());
+ SwitchConfigStatus scs2 = checkSwitchConfig(linkNode2);
+ if (scs2.getConfigState() == NetworkConfigState.DENY) {
+ return new LinkConfigStatus(NetworkConfigState.DENY, null,
+ "Link-node: " + linkNode2 + " denied by config: " + scs2.getMsg());
+ }
+ if (networkConfig.getRestrictLinks()) {
+ // default deny behavior
+ if (lkc == null) {
+ // link is not configured - we deny this link
+ return new LinkConfigStatus(NetworkConfigState.DENY, null,
+ "Link not configured, in network denying links by default.");
+ }
+ if (lkc.isAllowed()) {
+ // link is allowed in config, return configured attributes
+ return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
+ } else {
+ // link has been configured off (administratively down)
+ return new LinkConfigStatus(NetworkConfigState.DENY, null,
+ "Link configured down (allowed=false).");
+ }
+ } else {
+ // default allow behavior
+ if (lkc == null) {
+ // no config to add
+ return new LinkConfigStatus(NetworkConfigState.ACCEPT, null);
+ }
+ if (lkc.isAllowed()) {
+ // link is allowed in config, return configured attributes
+ return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
+ } else {
+ // link has been configured off (administratively down)
+ return new LinkConfigStatus(NetworkConfigState.DENY, null,
+ "Link configured down (allowed=false).");
+ }
+ }
+
+ }
+
+ @Override
+ public List<SwitchConfig> getConfiguredAllowedSwitches() {
+ List<SwitchConfig> allowed = new ArrayList<SwitchConfig>();
+ for (SwitchConfig swc : configuredSwitches.values()) {
+ if (swc.isAllowed()) {
+ allowed.add(swc);
+ }
+ }
+ return allowed;
+ }
+
+ @Override
+ public List<LinkConfig> getConfiguredAllowedLinks() {
+ List<LinkConfig> allowed = new ArrayList<LinkConfig>();
+ for (LinkConfig lkc : configuredLinks.values()) {
+ if (lkc.isAllowed()) {
+ allowed.add(lkc);
+ }
+ }
+ return allowed;
+ }
+
+ @Override
+ public List<List<String>> getOpticalReachabiltyConfig() {
+ if (networkConfig.getOpticalReachability() != null) {
+ return networkConfig.getOpticalReachability();
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Dpid getDpidForName(String name) {
+ if (nameToDpid.get(name) != null) {
+ return new Dpid(nameToDpid.get(name));
+ }
+ return null;
+ }
+
+ // **************
+ // Private methods
+ // **************
+
+ private void loadNetworkConfig(FloodlightModuleContext context) {
+ ObjectMapper mapper = new ObjectMapper();
+ networkConfig = new NetworkConfig();
+
+ Map<String, String> configParams = context.getConfigParams(this);
+ String file = configParams.get("networkConfigFile");
+ if (file == null) {
+ // use default file which no-ops
+ log.info("Using default file for network configuration");
+ file = DEFAULT_NETWORK_CONFIG_FILE;
+ } else {
+ log.info("Loading network configuration from " + file);
+ }
+
+ try {
+ networkConfig = mapper.readValue(new File(file), NetworkConfig.class);
+ } catch (JsonParseException e) {
+ String err = String.format("JsonParseException while loading network "
+ + "config from file: %s: %s", file, e.getMessage());
+ throw new NetworkConfigException.ErrorConfig(err);
+ } catch (JsonMappingException e) {
+ String err = String.format(
+ "JsonMappingException while loading network config "
+ + "from file: %s: %s", file, e.getMessage());
+ throw new NetworkConfigException.ErrorConfig(err);
+ } catch (IOException e) {
+ String err = String.format("IOException while loading network config "
+ + "from file: %s %s", file, e.getMessage());
+ throw new NetworkConfigException.ErrorConfig(err);
+ }
+
+ log.info("Network config specifies: {} switches and {} links",
+ (networkConfig.getRestrictSwitches())
+ ? networkConfig.getSwitchConfig().size() : "default allow",
+ (networkConfig.getRestrictLinks())
+ ? networkConfig.getLinkConfig().size() : "default allow");
+ }
+
+ private void parseNetworkConfig() {
+ List<SwitchConfig> swConfList = networkConfig.getSwitchConfig();
+ List<LinkConfig> lkConfList = networkConfig.getLinkConfig();
+ validateSwitchConfig(swConfList);
+ createTypeSpecificSwitchConfig(swConfList);
+ validateLinkConfig(lkConfList);
+ createTypeSpecificLinkConfig(lkConfList);
+ // TODO validate reachability matrix 'names' for configured dpids
+ }
+
+ private void createTypeSpecificSwitchConfig(List<SwitchConfig> swConfList) {
+ for (SwitchConfig swc : swConfList) {
+ nameToDpid.put(swc.getName(), swc.getDpid());
+ String swtype = swc.getType();
+ switch (swtype) {
+ case SEGMENT_ROUTER:
+ SwitchConfig sr = new SegmentRouterConfig(swc);
+ configuredSwitches.put(sr.getDpid(), sr);
+ break;
+ case ROADM:
+ SwitchConfig rd = new RoadmConfig(swc);
+ configuredSwitches.put(rd.getDpid(), rd);
+ break;
+ case OF10SWITCH:
+ SwitchConfig of10 = new SwitchOF10Config(swc);
+ configuredSwitches.put(of10.getDpid(), of10);
+ break;
+ default:
+ throw new NetworkConfigException.UnknownSwitchType(swtype,
+ swc.getName());
+ }
+ }
+ }
+
+ private void createTypeSpecificLinkConfig(List<LinkConfig> lkConfList) {
+ for (LinkConfig lkc : lkConfList) {
+ String lktype = lkc.getType();
+ switch (lktype) {
+ case PKT_LINK:
+ PktLinkConfig pk = new PktLinkConfig(lkc);
+ for (LinkTuple lt : pk.getLinkTupleList()) {
+ configuredLinks.put(lt, pk);
+ }
+ break;
+ case WDM_LINK:
+ WdmLinkConfig wd = new WdmLinkConfig(lkc);
+ for (LinkTuple lt : wd.getLinkTupleList()) {
+ configuredLinks.put(lt, wd);
+ }
+ break;
+ case PKT_OPT_LINK:
+ PktOptLinkConfig po = new PktOptLinkConfig(lkc);
+ for (LinkTuple lt : po.getLinkTupleList()) {
+ configuredLinks.put(lt, po);
+ }
+ break;
+ default:
+ throw new NetworkConfigException.UnknownLinkType(lktype,
+ lkc.getNodeDpid1(), lkc.getNodeDpid2());
+ }
+ }
+ }
+
+ private void validateSwitchConfig(List<SwitchConfig> swConfList) {
+ Set<Long> swDpids = new HashSet<Long>();
+ Set<String> swNames = new HashSet<String>();
+ for (SwitchConfig swc : swConfList) {
+ if (swc.getNodeDpid() == null || swc.getDpid() == 0) {
+ throw new NetworkConfigException.DpidNotSpecified(swc.getName());
+ }
+ // ensure both String and Long values of dpid are set
+ if (swc.getDpid() != HexString.toLong(swc.getNodeDpid())) {
+ throw new NetworkConfigException.SwitchDpidNotConverted(
+ swc.getName());
+ }
+ if (swc.getName() == null) {
+ throw new NetworkConfigException.NameNotSpecified(swc.getDpid());
+ }
+ if (swc.getType() == null) {
+ throw new NetworkConfigException.SwitchTypeNotSpecified(
+ swc.getDpid());
+ }
+ if (!swDpids.add(swc.getDpid())) {
+ throw new NetworkConfigException.DuplicateDpid(swc.getDpid());
+ }
+ if (!swNames.add(swc.getName())) {
+ throw new NetworkConfigException.DuplicateName(swc.getName());
+ }
+ // TODO Add more validations
+ }
+ }
+
+ private void validateLinkConfig(List<LinkConfig> lkConfList) {
+ for (LinkConfig lkc : lkConfList) {
+ if (lkc.getNodeDpid1() == null || lkc.getNodeDpid2() == null) {
+ throw new NetworkConfigException.LinkDpidNotSpecified(
+ lkc.getNodeDpid1(), lkc.getNodeDpid2());
+ }
+ // ensure both String and Long values are set
+ if (lkc.getDpid1() != HexString.toLong(lkc.getNodeDpid1()) ||
+ lkc.getDpid2() != HexString.toLong(lkc.getNodeDpid2())) {
+ throw new NetworkConfigException.LinkDpidNotConverted(
+ lkc.getNodeDpid1(), lkc.getNodeDpid2());
+ }
+ if (lkc.getType() == null) {
+ throw new NetworkConfigException.LinkTypeNotSpecified(
+ lkc.getNodeDpid1(), lkc.getNodeDpid2());
+ }
+ if (configuredSwitches.get(lkc.getDpid1()) == null) {
+ throw new NetworkConfigException.LinkForUnknownSwitchConfig(
+ lkc.getNodeDpid1());
+ }
+ if (configuredSwitches.get(lkc.getDpid2()) == null) {
+ throw new NetworkConfigException.LinkForUnknownSwitchConfig(
+ lkc.getNodeDpid2());
+ }
+ // TODO add more validations
+ }
+
+ }
+
+ private LinkConfig getConfiguredLink(Link link) {
+ LinkConfig lkc = null;
+ // first try the unidirectional link with the ports assigned
+ lkc = configuredLinks.get(new LinkTuple(
+ new SwitchPort(link.getSrc(), link.getSrcPort()),
+ new SwitchPort(link.getDst(), link.getDstPort())));
+ if (lkc == null) {
+ // try without ports, as configuration may be for all links
+ // between the two switches
+ lkc = configuredLinks.get(new LinkTuple(
+ new SwitchPort(link.getSrc(), (short) 0),
+ new SwitchPort(link.getDst(), (short) 0)));
+ }
+ return lkc;
+ }
+
+
+ // **************
+ // IFloodlightModule
+ // **************
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleServices() {
+ Collection<Class<? extends IFloodlightService>> l =
+ new ArrayList<Class<? extends IFloodlightService>>();
+ l.add(INetworkConfigService.class);
+ return l;
+ }
+
+ @Override
+ public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
+ Map<Class<? extends IFloodlightService>, IFloodlightService> m =
+ new HashMap<>();
+ m.put(INetworkConfigService.class, this);
+ return m;
+ }
+
+ @Override
+ public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+ loadNetworkConfig(context);
+ configuredSwitches = new ConcurrentHashMap<Long, SwitchConfig>();
+ configuredLinks = new ConcurrentHashMap<LinkTuple, LinkConfig>();
+ nameToDpid = new HashMap<String, Long>();
+ }
+
+ @Override
+ public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
+ parseNetworkConfig();
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java b/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java
new file mode 100644
index 0000000..f205686
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/PktLinkConfig.java
@@ -0,0 +1,159 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.LinkTuple;
+import net.onrc.onos.core.util.PortNumber;
+
+import org.codehaus.jackson.JsonNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Configuration for a link between two packet-switches.
+ */
+public class PktLinkConfig extends LinkConfig {
+ protected static final Logger log = LoggerFactory
+ .getLogger(PktLinkConfig.class);
+ private int port1;
+ private int port2;
+ private String nodeName1;
+ private String nodeName2;
+ private List<LinkTuple> linkTupleList;
+
+ public PktLinkConfig(LinkConfig lkc) {
+ nodeDpid1 = lkc.getNodeDpid1();
+ nodeDpid2 = lkc.getNodeDpid2();
+ dpid1 = lkc.getDpid1();
+ dpid2 = lkc.getDpid2();
+ type = lkc.getType();
+ allowed = lkc.isAllowed();
+ params = lkc.getParams();
+ publishAttributes = new ConcurrentHashMap<String, String>();
+ parseParams();
+ validateParams();
+ setPublishAttributes();
+ }
+
+ // ********************
+ // Packet Link Configuration
+ // ********************
+
+ public int getPort1() {
+ return port1;
+ }
+
+ public void setPort1(int port1) {
+ this.port1 = port1;
+ }
+
+ public int getPort2() {
+ return port2;
+ }
+
+ public void setPort2(int port2) {
+ this.port2 = port2;
+ }
+
+ public String getNodeName1() {
+ return nodeName1;
+ }
+
+ public void setNodeName1(String nodeName1) {
+ this.nodeName1 = nodeName1;
+ }
+
+ public String getNodeName2() {
+ return nodeName2;
+ }
+
+ public void setNodeName2(String nodeName2) {
+ this.nodeName2 = nodeName2;
+ }
+
+ /**
+ * Returns the two unidirectional links corresponding to the packet-link
+ * configuration. It is possible that the ports in the LinkTuple have
+ * portnumber '0', implying that the configuration applies to all links
+ * between the two switches.
+ *
+ * @return a list of LinkTuple with exactly 2 unidirectional links
+ */
+ public List<LinkTuple> getLinkTupleList() {
+ if (linkTupleList != null) {
+ return linkTupleList;
+ } else {
+ linkTupleList = new ArrayList<LinkTuple>();
+ }
+
+ // first one direction
+ linkTupleList.add(new LinkTuple(
+ new Dpid(nodeDpid1), PortNumber.uint32(port1),
+ new Dpid(nodeDpid2), PortNumber.uint32(port2)));
+ // then the reverse direction
+ linkTupleList.add(new LinkTuple(
+ new Dpid(nodeDpid2), PortNumber.uint32(port2),
+ new Dpid(nodeDpid1), PortNumber.uint32(port1)));
+ return linkTupleList;
+ }
+
+ private void setPublishAttributes() {
+
+ }
+
+ private void parseParams() {
+ if (params == null) {
+ throw new PktLinkParamsNotSpecified(nodeDpid1, nodeDpid2);
+ }
+ Set<Entry<String, JsonNode>> m = params.entrySet();
+ for (Entry<String, JsonNode> e : m) {
+ String key = e.getKey();
+ JsonNode j = e.getValue();
+ if (key.equals("nodeName1")) {
+ setNodeName1(j.asText());
+ } else if (key.equals("nodeName2")) {
+ setNodeName2(j.asText());
+ } else if (key.equals("port1")) {
+ setPort1(j.asInt());
+ } else if (key.equals("port2")) {
+ setPort2(j.asInt());
+ } else {
+ throw new UnknownPktLinkConfig(key, nodeDpid1, nodeDpid2);
+ }
+ }
+ }
+
+ private void validateParams() {
+ // TODO - wrong-names, duplicate links,
+ // duplicate use of port, is switch-allowed for which link is allowed?
+ }
+
+ public static class PktLinkParamsNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = 6247582323691265513L;
+
+ public PktLinkParamsNotSpecified(String dpidA, String dpidB) {
+ super();
+ log.error("Params required for packet link - not specified "
+ + "for link between switch1:{} and switch2:{}",
+ dpidA, dpidB);
+ }
+ }
+
+ public static class UnknownPktLinkConfig extends RuntimeException {
+ private static final long serialVersionUID = -5750132094884129179L;
+
+ public UnknownPktLinkConfig(String key, String dpidA, String dpidB) {
+ super();
+ log.error("Unknown packet-link config {} for link between"
+ + " dpid1: {} and dpid2: {}", key,
+ dpidA, dpidB);
+ }
+ }
+
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/PktOptLinkConfig.java b/src/main/java/net/onrc/onos/core/configmanager/PktOptLinkConfig.java
new file mode 100644
index 0000000..544edc3
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/PktOptLinkConfig.java
@@ -0,0 +1,19 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
+import net.onrc.onos.core.util.LinkTuple;
+
+public class PktOptLinkConfig extends LinkConfig {
+
+ public PktOptLinkConfig(LinkConfig lkc) {
+ // TODO Auto-generated constructor stub
+ }
+
+ public List<LinkTuple> getLinkTupleList() {
+ // TODO Auto-generated method stub
+ return Collections.emptyList(); // TODO change me
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/RoadmConfig.java b/src/main/java/net/onrc/onos/core/configmanager/RoadmConfig.java
new file mode 100644
index 0000000..e6d3489
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/RoadmConfig.java
@@ -0,0 +1,48 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RoadmConfig extends SwitchConfig {
+ protected static final Logger log = LoggerFactory
+ .getLogger(RoadmConfig.class);
+ private int numRegen;
+
+ public RoadmConfig(SwitchConfig swc) {
+ this.setName(swc.getName());
+ this.setDpid(swc.getDpid());
+ this.setType(swc.getType());
+ this.setLatitude(swc.getLatitude());
+ this.setLongitude(swc.getLongitude());
+ this.setParams(swc.getParams());
+ this.setAllowed(swc.isAllowed());
+ publishAttributes = new ConcurrentHashMap<String, String>();
+ parseParams();
+ validateParams();
+ setPublishAttributes();
+ }
+
+ public int getNumRegen() {
+ return numRegen;
+ }
+
+ public void setNumRegen(int numRegen) {
+ this.numRegen = numRegen;
+ }
+
+ private void parseParams() {
+ // TODO
+ }
+
+ private void validateParams() {
+ // TODO
+ }
+
+ private void setPublishAttributes() {
+ // TODO
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/SegmentRouterConfig.java b/src/main/java/net/onrc/onos/core/configmanager/SegmentRouterConfig.java
new file mode 100644
index 0000000..58121e2
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/SegmentRouterConfig.java
@@ -0,0 +1,257 @@
+package net.onrc.onos.core.configmanager;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.projectfloodlight.openflow.util.HexString;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SegmentRouterConfig extends SwitchConfig {
+ protected static final Logger log = LoggerFactory
+ .getLogger(SegmentRouterConfig.class);
+ private String routerIp;
+ private String routerMac;
+ private int nodeSid;
+ private List<AdjacencySid> adjacencySids;
+ private List<Subnet> subnets;
+
+ public static final String ROUTER_IP = "routerIp";
+ public static final String ROUTER_MAC = "routerMac";
+ public static final String NODE_SID = "nodeSid";
+ public static final String ADJACENCY_SIDS = "adjacencySids";
+ public static final String SUBNETS = "subnets";
+
+ public SegmentRouterConfig(SwitchConfig swc) {
+ this.setName(swc.getName());
+ this.setDpid(swc.getDpid());
+ this.setType(swc.getType());
+ this.setLatitude(swc.getLatitude());
+ this.setLongitude(swc.getLongitude());
+ this.setParams(swc.getParams());
+ this.setAllowed(swc.isAllowed());
+ publishAttributes = new ConcurrentHashMap<String, String>();
+ adjacencySids = new ArrayList<AdjacencySid>();
+ subnets = new ArrayList<Subnet>();
+ parseParams();
+ validateParams();
+ setPublishAttributes();
+ }
+
+ // ********************
+ // Segment Router Configuration
+ // ********************
+ public String getRouterIp() {
+ return routerIp;
+ }
+
+ public void setRouterIp(String routerIp) {
+ this.routerIp = routerIp;
+ }
+
+ public String getRouterMac() {
+ return routerMac;
+ }
+
+ public void setRouterMac(String routerMac) {
+ this.routerMac = routerMac;
+ }
+
+ public int getNodeSid() {
+ return nodeSid;
+ }
+
+ public void setNodeSid(int nodeSid) {
+ this.nodeSid = nodeSid;
+ }
+
+ public static class AdjacencySid {
+ private int portNo;
+ private int adjSid;
+
+ public AdjacencySid(int portNo, int adjSid) {
+ this.portNo = portNo;
+ this.adjSid = adjSid;
+ }
+
+ public int getPortNo() {
+ return portNo;
+ }
+
+ public void setPortNo(int portNo) {
+ this.portNo = portNo;
+ }
+
+ public int getAdjSid() {
+ return adjSid;
+ }
+
+ public void setAdjSid(int adjSid) {
+ this.adjSid = adjSid;
+ }
+ }
+
+ public List<AdjacencySid> getAdjacencySids() {
+ return adjacencySids;
+ }
+
+ public void setAdjacencySids(List<AdjacencySid> adjacencySids) {
+ this.adjacencySids = adjacencySids;
+ }
+
+ public static class Subnet {
+ private int portNo;
+ private String subnetIp;
+
+ public Subnet(int portNo, String subnetIp) {
+ this.portNo = portNo;
+ this.subnetIp = subnetIp;
+ }
+
+ public int getPortNo() {
+ return portNo;
+ }
+
+ public void setPortNo(int portNo) {
+ this.portNo = portNo;
+ }
+
+ public String getSubnetIp() {
+ return subnetIp;
+ }
+
+ public void setSubnetIp(String subnetIp) {
+ this.subnetIp = subnetIp;
+ }
+ }
+
+ public List<Subnet> getSubnets() {
+ return subnets;
+ }
+
+ public void setSubnets(List<Subnet> subnets) {
+ this.subnets = subnets;
+ }
+
+ // ********************
+ // Helper methods
+ // ********************
+
+ private void parseParams() {
+ if (params == null) {
+ throw new NetworkConfigException.ParamsNotSpecified(name);
+ }
+
+ Set<Entry<String, JsonNode>> m = params.entrySet();
+ for (Entry<String, JsonNode> e : m) {
+ String key = e.getKey();
+ JsonNode j = e.getValue();
+ if (key.equals("routerIp")) {
+ setRouterIp(j.asText());
+ } else if (key.equals("routerMac")) {
+ setRouterMac(j.asText());
+ } else if (key.equals("nodeSid")) {
+ setNodeSid(j.asInt());
+ } else if (key.equals("adjacencySids") || key.equals("subnets")) {
+ getInnerParams(j, key);
+ } else {
+ throw new UnknownSegmentRouterConfig(key, dpid);
+ }
+ }
+ }
+
+ private void getInnerParams(JsonNode j, String innerParam) {
+ Iterator<JsonNode> innerList = j.getElements();
+ while (innerList.hasNext()) {
+ Iterator<Entry<String, JsonNode>> f = innerList.next().getFields();
+ int portNo = -1;
+ int adjSid = -1;
+ String subnetIp = null;
+ while (f.hasNext()) {
+ Entry<String, JsonNode> fe = f.next();
+ if (fe.getKey().equals("portNo")) {
+ portNo = fe.getValue().asInt();
+ } else if (fe.getKey().equals("adjSid")) {
+ adjSid = fe.getValue().asInt();
+ } else if (fe.getKey().equals("subnetIp")) {
+ subnetIp = fe.getValue().asText();
+ } else {
+ throw new UnknownSegmentRouterConfig(fe.getKey(), dpid);
+ }
+ }
+ if (innerParam.equals("adjacencySids")) {
+ AdjacencySid ads = new AdjacencySid(portNo, adjSid);
+ adjacencySids.add(ads);
+ } else {
+ Subnet sip = new Subnet(portNo, subnetIp);
+ subnets.add(sip);
+ }
+ }
+ }
+
+ private void validateParams() {
+ if (routerIp == null) {
+ throw new IpNotSpecified(dpid);
+ }
+
+ // TODO more validations
+ }
+
+ /**
+ * Setting publishAttributes implies that this is the configuration that
+ * will be added to Topology.Switch object before it is published on the
+ * channel to other controller instances.
+ */
+ private void setPublishAttributes() {
+ publishAttributes.put(ROUTER_IP, routerIp);
+ publishAttributes.put(ROUTER_MAC, routerMac);
+ publishAttributes.put(NODE_SID, String.valueOf(nodeSid));
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ publishAttributes.put(ADJACENCY_SIDS,
+ mapper.writeValueAsString(adjacencySids));
+ publishAttributes.put(SUBNETS,
+ mapper.writeValueAsString(subnets));
+ } catch (JsonProcessingException e) {
+ log.error("Error while writing SR config: {}", e.getCause());
+ } catch (IOException e) {
+ log.error("Error while writing SR config: {}", e.getCause());
+ }
+ }
+
+ // ********************
+ // Exceptions
+ // ********************
+
+ public static class IpNotSpecified extends RuntimeException {
+ private static final long serialVersionUID = -3001502553646331686L;
+
+ public IpNotSpecified(long dpid) {
+ super();
+ log.error("Router IP address not specified for SR config dpid:{}",
+ HexString.toHexString(dpid));
+ }
+ }
+
+ public static class UnknownSegmentRouterConfig extends RuntimeException {
+ private static final long serialVersionUID = -5750132094884129179L;
+
+ public UnknownSegmentRouterConfig(String key, long dpid) {
+ super();
+ log.error("Unknown Segment Router config {} in dpid: {}", key,
+ HexString.toHexString(dpid));
+ }
+ }
+
+
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/SwitchOF10Config.java b/src/main/java/net/onrc/onos/core/configmanager/SwitchOF10Config.java
new file mode 100644
index 0000000..3b56521
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/SwitchOF10Config.java
@@ -0,0 +1,39 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SwitchOF10Config extends SwitchConfig {
+ protected static final Logger log = LoggerFactory
+ .getLogger(RoadmConfig.class);
+
+ public SwitchOF10Config(SwitchConfig swc) {
+ this.setName(swc.getName());
+ this.setDpid(swc.getDpid());
+ this.setType(swc.getType());
+ this.setLatitude(swc.getLatitude());
+ this.setLongitude(swc.getLongitude());
+ this.setParams(swc.getParams());
+ this.setAllowed(swc.isAllowed());
+ publishAttributes = new ConcurrentHashMap<String, String>();
+ parseParams();
+ validateParams();
+ setPublishAttributes();
+ }
+
+ private void parseParams() {
+ // TODO
+ }
+
+ private void validateParams() {
+ // TODO
+ }
+
+ private void setPublishAttributes() {
+ // TODO
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/configmanager/WdmLinkConfig.java b/src/main/java/net/onrc/onos/core/configmanager/WdmLinkConfig.java
new file mode 100644
index 0000000..fff3005
--- /dev/null
+++ b/src/main/java/net/onrc/onos/core/configmanager/WdmLinkConfig.java
@@ -0,0 +1,19 @@
+package net.onrc.onos.core.configmanager;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
+import net.onrc.onos.core.util.LinkTuple;
+
+public class WdmLinkConfig extends LinkConfig {
+
+ public WdmLinkConfig(LinkConfig lkc) {
+ // TODO Auto-generated constructor stub
+ }
+
+ public List<LinkTuple> getLinkTupleList() {
+ // TODO Auto-generated method stub
+ return Collections.emptyList(); // TODO change me
+ }
+}
diff --git a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
index 7bdf041..8d7aecb 100644
--- a/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
+++ b/src/main/java/net/onrc/onos/core/drivermanager/OFSwitchImplCPqD13.java
@@ -125,9 +125,9 @@
if (!usePipeline13) {
// Send packet-in to controller if a packet misses the first table
populateTableMissEntry(0, true, false, false, 0);
- } //else {
- // configureSwitch();
- //}
+ } // else {
+ // configureSwitch();
+ // }
sendBarrier(true);
}
diff --git a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
index be47051..9ef6fa9 100644
--- a/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
+++ b/src/main/java/net/onrc/onos/core/topology/TopologyPublisher.java
@@ -7,6 +7,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -24,8 +25,11 @@
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.core.util.SingletonTask;
import net.floodlightcontroller.threadpool.IThreadPoolService;
-
import net.onrc.onos.api.batchoperation.BatchOperationEntry;
+import net.onrc.onos.core.configmanager.INetworkConfigService;
+import net.onrc.onos.core.configmanager.INetworkConfigService.LinkConfigStatus;
+import net.onrc.onos.core.configmanager.INetworkConfigService.NetworkConfigState;
+import net.onrc.onos.core.configmanager.INetworkConfigService.SwitchConfigStatus;
import net.onrc.onos.core.datagrid.IDatagridService;
import net.onrc.onos.core.datagrid.IEventChannel;
import net.onrc.onos.core.hostmanager.Host;
@@ -74,8 +78,8 @@
private IDatagridService datagridService;
private IHostService hostService;
-
private MutableTopology mutableTopology;
+ private INetworkConfigService networkConfigService;
private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
private boolean cleanupEnabled = true;
@@ -288,6 +292,13 @@
@Override
public void linkAdded(Link link) {
+ LinkConfigStatus ret = networkConfigService.checkLinkConfig(link);
+ if (ret.getConfigState() == NetworkConfigState.DENY) {
+ log.warn("Discovered {} denied by configuration. {} "
+ + "Not allowing it to proceed.", link, ret.getMsg());
+ return;
+ }
+
LinkData linkData = new LinkData(
new SwitchPort(link.getSrc(), link.getSrcPort()),
new SwitchPort(link.getDst(), link.getDstPort()));
@@ -297,8 +308,17 @@
// TODO populate appropriate attributes.
linkData.createStringAttribute(TopologyElement.TYPE,
TopologyElement.TYPE_PACKET_LAYER);
- linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
- ConfigState.NOT_CONFIGURED.toString());
+ if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
+ Map<String, String> attr = ret.getLinkConfig().getPublishAttributes();
+ for (Entry<String, String> e : attr.entrySet()) {
+ linkData.createStringAttribute(e.getKey(), e.getValue());
+ }
+ linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.CONFIGURED.toString());
+ } else {
+ linkData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.NOT_CONFIGURED.toString());
+ }
linkData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
AdminStatus.ACTIVE.toString());
linkData.freeze();
@@ -335,6 +355,13 @@
return;
}
+ SwitchConfigStatus ret = networkConfigService.checkSwitchConfig(dpid);
+ if (ret.getConfigState() == NetworkConfigState.DENY) {
+ log.warn("Activated switch {} denied by network configuration. {} "
+ + "Not allowing it to proceed.", dpid, ret.getMsg());
+ return;
+ }
+
controllerRoleChanged(dpid, Role.MASTER);
SwitchData switchData = new SwitchData(dpid);
@@ -345,10 +372,19 @@
TopologyElement.TYPE_PACKET_LAYER);
switchData.createStringAttribute("ConnectedSince",
sw.getConnectedSince().toString());
- switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
- ConfigState.NOT_CONFIGURED.toString());
switchData.createStringAttribute(TopologyElement.ELEMENT_ADMIN_STATUS,
AdminStatus.ACTIVE.toString());
+ if (ret.getConfigState() == NetworkConfigState.ACCEPT_ADD) {
+ Map<String, String> attr = ret.getSwitchConfig().getPublishAttributes();
+ for (Entry<String, String> e : attr.entrySet()) {
+ switchData.createStringAttribute(e.getKey(), e.getValue());
+ }
+ switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.CONFIGURED.toString());
+ } else {
+ switchData.createStringAttribute(TopologyElement.ELEMENT_CONFIG_STATE,
+ ConfigState.NOT_CONFIGURED.toString());
+ }
switchData.freeze();
// The Port events
List<PortData> portDataEntries = new ArrayList<PortData>();
@@ -516,6 +552,7 @@
l.add(IDatagridService.class);
l.add(ITopologyService.class);
l.add(IHostService.class);
+ l.add(INetworkConfigService.class);
return l;
}
@@ -527,6 +564,7 @@
registryService = context.getServiceImpl(IControllerRegistryService.class);
datagridService = context.getServiceImpl(IDatagridService.class);
hostService = context.getServiceImpl(IHostService.class);
+ networkConfigService = context.getServiceImpl(INetworkConfigService.class);
topologyService = context.getServiceImpl(ITopologyService.class);
}
diff --git a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
index 2346e21..8197724 100644
--- a/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
+++ b/src/main/resources/META-INF/services/net.floodlightcontroller.core.module.IFloodlightModule
@@ -27,3 +27,4 @@
net.onrc.onos.core.newintent.IntentFloodlightModule
net.onrc.onos.core.matchaction.MatchActionModule
net.onrc.onos.core.flowmanager.FlowManagerModule
+net.onrc.onos.core.configmanager.NetworkConfigManager