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/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