diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5e76326
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+#ignore eclipse workspace metadata folder
+.metadata/**
+eclipse_preferences.epf
+StartingPoint/**
+RemoteSystemsTempFiles/**
+wc-templates/**
+**/.settings/**
+**/.recommenders/**
+.project
+.classpath
+.DS_Store
+#maven target folder
+**/target/**
+dependency-reduced-pom.xml
+build.log
+.sonarlint/**
+
+## IntelliJ Stuff
+.idea
+*.iml
+
+## Binaries
+*.tar.gz
+
+*.pydevproject
diff --git a/opensync_ext_interface/pom.xml b/opensync_ext_interface/pom.xml
new file mode 100644
index 0000000..74fb292
--- /dev/null
+++ b/opensync_ext_interface/pom.xml
@@ -0,0 +1,20 @@
+
+ 4.0.0
+ ai.connectus
+ opensync_ext_interface
+ 0.0.1-SNAPSHOT
+ opensync_ext_interface
+ Interface that defines how opensync gateway gets the AP config
+
+
+ com.whizcontrol
+ base-models
+ 0.0.1-SNAPSHOT
+
+
+ ai.connectus
+ opensync_protobuf
+ 0.0.1-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/OpensyncExternalIntegrationInterface.java b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/OpensyncExternalIntegrationInterface.java
new file mode 100644
index 0000000..ff0ed6e
--- /dev/null
+++ b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/OpensyncExternalIntegrationInterface.java
@@ -0,0 +1,15 @@
+package ai.connectus.opensync.external.integration;
+
+import ai.connectus.opensync.external.integration.models.OpensyncAPConfig;
+import sts.PlumeStats.Report;
+import traffic.NetworkMetadata.FlowReport;
+import wc.stats.IpDnsTelemetry.WCStatsReport;
+
+public interface OpensyncExternalIntegrationInterface {
+ void apConnected(String apId);
+ void apDisconnected(String apId);
+ OpensyncAPConfig getApConfig(String apId);
+ void processMqttMessage(String topic, Report report);
+ void processMqttMessage(String topic, FlowReport flowReport);
+ void processMqttMessage(String topic, WCStatsReport wcStatsReport);
+}
diff --git a/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPConfig.java b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPConfig.java
new file mode 100644
index 0000000..2991e44
--- /dev/null
+++ b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPConfig.java
@@ -0,0 +1,81 @@
+package ai.connectus.opensync.external.integration.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.whizcontrol.core.model.equipment.RadioType;
+import com.whizcontrol.core.model.json.BaseJsonModel;
+
+public class OpensyncAPConfig extends BaseJsonModel {
+
+ private static final long serialVersionUID = 3917975477206236668L;
+
+ private OpensyncAPRadioConfig radioConfig;
+ private List ssidConfigs;
+
+
+ public OpensyncAPRadioConfig getRadioConfig() {
+ return radioConfig;
+ }
+
+
+ public void setRadioConfig(OpensyncAPRadioConfig radioConfig) {
+ this.radioConfig = radioConfig;
+ }
+
+
+ public List getSsidConfigs() {
+ return ssidConfigs;
+ }
+
+
+ public void setSsidConfigs(List ssidConfigs) {
+ this.ssidConfigs = ssidConfigs;
+ }
+
+
+ @Override
+ public OpensyncAPConfig clone() {
+ OpensyncAPConfig ret = (OpensyncAPConfig)super.clone();
+ if(radioConfig!=null) {
+ ret.radioConfig = radioConfig.clone();
+ }
+
+ if(ssidConfigs!=null) {
+ ret.ssidConfigs = new ArrayList();
+ for(OpensyncAPSsidConfig s: ssidConfigs) {
+ ret.ssidConfigs.add(s.clone());
+ }
+ }
+
+ return ret;
+ }
+
+ public static void main(String[] args) {
+ OpensyncAPConfig cfg = new OpensyncAPConfig();
+ cfg.radioConfig = new OpensyncAPRadioConfig();
+ cfg.ssidConfigs = new ArrayList();
+
+ cfg.radioConfig.setRadioChannel24G(1);
+ cfg.radioConfig.setRadioChannel5LG(44);
+ cfg.radioConfig.setRadioChannel5HG(108);
+
+ OpensyncAPSsidConfig ssidCfg = new OpensyncAPSsidConfig();
+ ssidCfg.setRadioType(RadioType.is2dot4GHz);
+ ssidCfg.setSsid("Connectus-standalone");
+ ssidCfg.setEncryption("WPA-PSK");
+ ssidCfg.setKey("12345678");
+ ssidCfg.setMode("2");
+ cfg.ssidConfigs.add(ssidCfg);
+
+ ssidCfg = new OpensyncAPSsidConfig();
+ ssidCfg.setRadioType(RadioType.is5GHz);
+ ssidCfg.setSsid("Connectus-standalone-5");
+ ssidCfg.setEncryption("WPA-PSK");
+ ssidCfg.setKey("12345678");
+ ssidCfg.setMode("2");
+ cfg.ssidConfigs.add(ssidCfg);
+
+ System.out.println(cfg.toPrettyString());
+ }
+}
diff --git a/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPRadioConfig.java b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPRadioConfig.java
new file mode 100644
index 0000000..c7da12a
--- /dev/null
+++ b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPRadioConfig.java
@@ -0,0 +1,50 @@
+package ai.connectus.opensync.external.integration.models;
+
+import com.whizcontrol.core.model.json.BaseJsonModel;
+
+public class OpensyncAPRadioConfig extends BaseJsonModel {
+
+ private static final long serialVersionUID = 5683558403622855381L;
+
+ private String country;
+ private int radioChannel24G;
+ private int radioChannel5LG;
+ private int radioChannel5HG;
+
+ public int getRadioChannel24G() {
+ return radioChannel24G;
+ }
+
+ public void setRadioChannel24G(int radioChannel24G) {
+ this.radioChannel24G = radioChannel24G;
+ }
+
+ public int getRadioChannel5LG() {
+ return radioChannel5LG;
+ }
+
+ public void setRadioChannel5LG(int radioChannel5LG) {
+ this.radioChannel5LG = radioChannel5LG;
+ }
+
+ public int getRadioChannel5HG() {
+ return radioChannel5HG;
+ }
+
+ public void setRadioChannel5HG(int radioChannel5HG) {
+ this.radioChannel5HG = radioChannel5HG;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ @Override
+ public OpensyncAPRadioConfig clone() {
+ return (OpensyncAPRadioConfig)super.clone();
+ }
+}
diff --git a/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPSsidConfig.java b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPSsidConfig.java
new file mode 100644
index 0000000..f9f7606
--- /dev/null
+++ b/opensync_ext_interface/src/main/java/ai/connectus/opensync/external/integration/models/OpensyncAPSsidConfig.java
@@ -0,0 +1,70 @@
+package ai.connectus.opensync.external.integration.models;
+
+import com.whizcontrol.core.model.equipment.RadioType;
+import com.whizcontrol.core.model.json.BaseJsonModel;
+
+public class OpensyncAPSsidConfig extends BaseJsonModel {
+
+ private static final long serialVersionUID = -8540144450360788799L;
+
+ private RadioType radioType;
+ private String ssid;
+ private String encryption;
+ private String key;
+ private String mode;
+ private boolean broadcast;
+
+ public RadioType getRadioType() {
+ return radioType;
+ }
+
+ public void setRadioType(RadioType radioType) {
+ this.radioType = radioType;
+ }
+
+ public String getSsid() {
+ return ssid;
+ }
+
+ public void setSsid(String ssid) {
+ this.ssid = ssid;
+ }
+
+ public String getEncryption() {
+ return encryption;
+ }
+
+ public void setEncryption(String encryption) {
+ this.encryption = encryption;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public boolean isBroadcast() {
+ return broadcast;
+ }
+
+ public void setBroadcast(boolean broadcast) {
+ this.broadcast = broadcast;
+ }
+
+ @Override
+ public OpensyncAPSsidConfig clone() {
+ return (OpensyncAPSsidConfig)super.clone();
+ }
+
+}
diff --git a/opensync_ext_static/pom.xml b/opensync_ext_static/pom.xml
new file mode 100644
index 0000000..13b03a7
--- /dev/null
+++ b/opensync_ext_static/pom.xml
@@ -0,0 +1,15 @@
+
+ 4.0.0
+ ai.connectus
+ opensync_ext_static
+ 0.0.1-SNAPSHOT
+ opensync_ext_static
+ Configuration interface that provides static config from the file
+
+
+ ai.connectus
+ opensync_ext_interface
+ 0.0.1-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/opensync_ext_static/src/main/java/ai/connectus/opensync/external/integration/OpensyncExternalIntegrationSimple.java b/opensync_ext_static/src/main/java/ai/connectus/opensync/external/integration/OpensyncExternalIntegrationSimple.java
new file mode 100644
index 0000000..298326b
--- /dev/null
+++ b/opensync_ext_static/src/main/java/ai/connectus/opensync/external/integration/OpensyncExternalIntegrationSimple.java
@@ -0,0 +1,59 @@
+package ai.connectus.opensync.external.integration;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import ai.connectus.opensync.external.integration.OpensyncExternalIntegrationInterface;
+import ai.connectus.opensync.external.integration.models.OpensyncAPConfig;
+import sts.PlumeStats.Report;
+import traffic.NetworkMetadata.FlowReport;
+import wc.stats.IpDnsTelemetry.WCStatsReport;
+
+@Component
+public class OpensyncExternalIntegrationSimple implements OpensyncExternalIntegrationInterface {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OpensyncExternalIntegrationSimple.class);
+
+ @Value("${connectus.ovsdb.configFileName:/Users/dtop/Documents/opensync_ext_static/src/main/resources/config_2_ssids.json}")
+ private String configFileName;
+
+ public void apConnected(String apId) {
+ LOG.info("AP {} got connected to the gateway", apId);
+ }
+
+ public void apDisconnected(String apId) {
+ LOG.info("AP {} got disconnected from the gateway", apId);
+ }
+
+ public OpensyncAPConfig getApConfig(String apId) {
+ LOG.info("Retrieving config for AP {} from file {}", apId, configFileName);
+ OpensyncAPConfig ret = null;
+
+ try {
+ ret = OpensyncAPConfig.fromFile(configFileName, OpensyncAPConfig.class);
+ } catch (IOException e) {
+ LOG.error("Cannot read config from {}", configFileName, e);
+ }
+
+ LOG.debug("Config content : {}", ret);
+
+ return ret;
+ }
+
+ public void processMqttMessage(String topic, Report report) {
+ LOG.info("Received report on topic {} for ap {}", topic, report.getNodeID());
+ }
+
+ public void processMqttMessage(String topic, FlowReport flowReport) {
+ LOG.info("Received flowReport on topic {} for ap {}", topic, flowReport.getObservationPoint().getNodeId());
+ }
+
+ public void processMqttMessage(String topic, WCStatsReport wcStatsReport) {
+ LOG.info("Received wcStatsReport on topic {} for ap {}", topic, wcStatsReport.getObservationPoint().getNodeId());
+ }
+
+}
diff --git a/opensync_ext_static/src/main/resources/config_2_ssids.json b/opensync_ext_static/src/main/resources/config_2_ssids.json
new file mode 100644
index 0000000..6486caf
--- /dev/null
+++ b/opensync_ext_static/src/main/resources/config_2_ssids.json
@@ -0,0 +1,27 @@
+{
+ "_type" : "OpensyncAPConfig",
+ "radioConfig" : {
+ "_type" : "OpensyncAPRadioConfig",
+ "country" : "CA",
+ "radioChannel24G" : 1,
+ "radioChannel5LG" : 44,
+ "radioChannel5HG" : 108
+ },
+ "ssidConfigs" : [ {
+ "_type" : "OpensyncAPSsidConfig",
+ "radioType" : "is2dot4GHz",
+ "ssid" : "Connectus-local",
+ "encryption" : "WPA-PSK",
+ "key" : "12345678",
+ "mode" : "2",
+ "broadcast" : true
+ }, {
+ "_type" : "OpensyncAPSsidConfig",
+ "radioType" : "is5GHz",
+ "ssid" : "Connectus-local-5",
+ "encryption" : "WPA-PSK",
+ "key" : "12345678",
+ "mode" : "2",
+ "broadcast" : true
+ } ]
+}
diff --git a/opensync_gateway/pom.xml b/opensync_gateway/pom.xml
new file mode 100644
index 0000000..e22e003
--- /dev/null
+++ b/opensync_gateway/pom.xml
@@ -0,0 +1,78 @@
+
+ 4.0.0
+
+ com.whizcontrol
+ root-pom
+ 0.0.1-SNAPSHOT
+
+ ai.connectus
+ opensync_experiment
+ opensync_experiment
+ Redirector and Controller for OpenSync
+
+
+ ai.connectus.opensync.experiment.OpenSyncProcess
+
+
+
+
+ base-container
+ com.whizcontrol
+ ${whizcontrol.release.version}
+
+
+ ai.connectus
+ opensync_ext_interface
+ 0.0.1-SNAPSHOT
+
+
+ ai.connectus
+ opensync_ext_static
+ 0.0.1-SNAPSHOT
+
+
+
+ com.vmware.ovsdb
+ ovsdb-client
+ 1.0.1
+
+
+ slf4j-log4j12
+ org.slf4j
+
+
+
+
+
+
+ ai.connectus
+ opensync_protobuf
+ 0.0.1-SNAPSHOT
+
+
+
+ com.google.protobuf
+ protobuf-java-util
+ 3.11.1
+
+
+
+ org.fusesource.mqtt-client
+ mqtt-client
+ 1.12
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/experiment/OpenSyncExperimentController.java b/opensync_gateway/src/main/java/ai/connectus/opensync/experiment/OpenSyncExperimentController.java
new file mode 100644
index 0000000..823fb5e
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/experiment/OpenSyncExperimentController.java
@@ -0,0 +1,31 @@
+package ai.connectus.opensync.experiment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import ai.connectus.opensync.ovsdb.ConnectusOvsdbClient;
+
+@RestController
+public class OpenSyncExperimentController {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OpenSyncExperimentController.class);
+
+ @Autowired
+ ConnectusOvsdbClient connectusOvsdbClient;
+
+ @RequestMapping(value = "/connectedClients", method = RequestMethod.GET)
+ public List getConnectedClients()
+ {
+ List ret = new ArrayList(connectusOvsdbClient.getConnectedClientIds());
+ LOG.info("Returning connected clients {}", ret);
+ return ret;
+ }
+
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/experiment/OpenSyncProcess.java b/opensync_gateway/src/main/java/ai/connectus/opensync/experiment/OpenSyncProcess.java
new file mode 100644
index 0000000..1dfcd98
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/experiment/OpenSyncProcess.java
@@ -0,0 +1,22 @@
+package ai.connectus.opensync.experiment;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+
+@ComponentScan(basePackages={"com.whizcontrol", "ai.connectus"})
+@EnableAutoConfiguration
+public class OpenSyncProcess {
+
+ /**
+ *
{@code java -Dssl.props=file:./ssl.properties -Dlogback.configurationFile=file:./logback.xml -jar ./opensync-experiment-0.0.1-SNAPSHOT.jar}
+ *
+ * @param args
+ */
+ public static void main(String[] args) {
+ ConfigurableApplicationContext applicationContext = SpringApplication.run(OpenSyncProcess.class, args);
+ // signal start of the application context
+ applicationContext.start();
+ }
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/mqtt/OpensyncMqttClient.java b/opensync_gateway/src/main/java/ai/connectus/opensync/mqtt/OpensyncMqttClient.java
new file mode 100644
index 0000000..fef8729
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/mqtt/OpensyncMqttClient.java
@@ -0,0 +1,208 @@
+package ai.connectus.opensync.mqtt;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.fusesource.mqtt.client.BlockingConnection;
+import org.fusesource.mqtt.client.MQTT;
+import org.fusesource.mqtt.client.Message;
+import org.fusesource.mqtt.client.QoS;
+import org.fusesource.mqtt.client.Topic;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.stereotype.Component;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.util.JsonFormat;
+import com.google.protobuf.util.JsonFormat.TypeRegistry;
+
+import ai.connectus.opensync.external.integration.OpensyncExternalIntegrationInterface;
+import ai.connectus.opensync.util.ZlibUtil;
+import sts.PlumeStats;
+import sts.PlumeStats.Report;
+import traffic.NetworkMetadata;
+import traffic.NetworkMetadata.FlowReport;
+import wc.stats.IpDnsTelemetry;
+import wc.stats.IpDnsTelemetry.WCStatsReport;
+
+@Component
+public class OpensyncMqttClient implements ApplicationListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OpensyncMqttClient.class);
+
+ private static final Logger MQTT_LOG = LoggerFactory.getLogger("MQTT_DATA");
+
+ public static Charset utf8 = Charset.forName("UTF-8");
+
+ @Autowired
+ private OpensyncExternalIntegrationInterface extIntegrationInterface;
+
+
+ //
+ // See https://github.com/fusesource/mqtt-client for the docs
+ //
+
+ private boolean keepReconnecting = true;
+ private Thread mqttClientThread;
+
+ public OpensyncMqttClient(
+ @Autowired io.netty.handler.ssl.SslContext sslContext,
+ @Value("${connectus.mqttBroker.address:testportal.123wlan.com}")
+ String mqttBrokerAddress,
+ @Value("${connectus.mqttBroker.listenPort:1883}")
+ int mqttBrokerListenPort
+ ){
+ String username = "admin";
+ String password = "admin";
+
+ Runnable mqttClientRunnable = () -> {
+ while(keepReconnecting) {
+ BlockingConnection connection = null;
+ try {
+ // Create a new MQTT connection to the broker.
+ /*
+ * Using SSL connections
+ * If you want to connect over SSL/TLS instead of
+ * TCP, use an "ssl://" or "tls://" URI prefix instead of "tcp://" for
+ * the host field.
+ * Supported protocol values are:
+ *
+ * ssl:// - Use the JVM default version of the SSL algorithm.
+ * sslv*:// - Use a specific SSL version where * is a version supported by your JVM. Example: sslv3
+ * tls:// - Use the JVM default version of the TLS algorithm.
+ * tlsv*:// - Use a specific TLS version where * is a version supported by your JVM. Example: tlsv1.1
+ * The client will use the
+ * default JVM SSLContext which is configured via JVM system properties
+ * unless you configure the MQTT instance using the setSslContext method.
+ *
+ * SSL connections perform blocking operations against internal thread
+ * pool unless you call the setBlockingExecutor method to configure that
+ * executor they will use instead.
+ *
+ */
+
+ MQTT mqtt = new MQTT();
+ //mqtt.setHost("tcp://192.168.0.137:61616");
+ mqtt.setHost("tls://"+mqttBrokerAddress+":"+mqttBrokerListenPort);
+ LOG.info("Connecting to Artemis using MQTT at {}", mqtt.getHost());
+ mqtt.setClientId("opensync_mqtt");
+ mqtt.setUserName(username);
+ mqtt.setPassword(password);
+ //Note: the following does not work with the serverContext, it has to be the clientContext
+ //mqtt.setSslContext(((JdkSslContext) sslContext).context());
+ //For now we'll rely on regular SSLContext from the JDK
+
+ //TODO: revisit this blocking connection, change it to futureConnection
+ connection = mqtt.blockingConnection();
+ connection.connect();
+ LOG.info("Connected to Artemis cluster at {}", mqtt.getHost());
+
+ // Subscribe to topics:
+ //
+ // new Topic("mqtt/example/publish", QoS.AT_LEAST_ONCE),
+ // new Topic("#", QoS.AT_LEAST_ONCE),
+ // new Topic("test/#", QoS.EXACTLY_ONCE),
+ // new Topic("foo/+/bar", QoS.AT_LEAST_ONCE)
+ Topic[] topics = {
+ new Topic("#", QoS.AT_LEAST_ONCE),
+ };
+
+ connection.subscribe(topics);
+ LOG.info("Subscribed to mqtt topics {}", Arrays.asList(topics));
+
+ //prepare a JSONPrinter to format protobuf messages as json
+ List protobufDescriptors = new ArrayList<>();
+ protobufDescriptors.addAll(PlumeStats.getDescriptor().getMessageTypes());
+ protobufDescriptors.addAll(IpDnsTelemetry.getDescriptor().getMessageTypes());
+ protobufDescriptors.addAll(NetworkMetadata.getDescriptor().getMessageTypes());
+ TypeRegistry oldRegistry = TypeRegistry.newBuilder().add(protobufDescriptors).build();
+ JsonFormat.Printer jsonPrinter = JsonFormat.printer().includingDefaultValueFields().omittingInsignificantWhitespace().usingTypeRegistry(oldRegistry );
+
+ //main loop - receive messages
+ while(true) {
+ Message mqttMsg = connection.receive(5, TimeUnit.SECONDS);
+
+ if(mqttMsg == null) {
+ continue;
+ }
+
+ byte payload[] = mqttMsg.getPayload();
+ //we acknowledge right after receive because:
+ // a. none of the stats messages are so important that we cannot skip one
+ // b. if there's some kind of problem with the message (decoding or processing) - we want to move on as quickly as possible and not let it get stuck in the queue
+ mqttMsg.ack();
+
+ LOG.trace("received message on topic {} size {}", mqttMsg.getTopic(), payload.length);
+
+ if(payload[0]==0x78) {
+ //looks like zlib-compressed data, let's decompress it before deserializing
+ payload = ZlibUtil.decompress(payload);
+ }
+
+ //attempt to parse the message as protobuf
+ MessageOrBuilder encodedMsg = null;
+
+ try {
+ encodedMsg = Report.parseFrom(payload);
+ MQTT_LOG.debug("topic = {} Report = {}", mqttMsg.getTopic(), jsonPrinter.print(encodedMsg));
+ extIntegrationInterface.processMqttMessage(mqttMsg.getTopic(), (Report) encodedMsg);
+
+ }catch(Exception e) {
+ try {
+ //not a plume_stats report, attempt to deserialize as network_metadata
+ encodedMsg = FlowReport.parseFrom(payload);
+ MQTT_LOG.debug("topic = {} FlowReport = {}", mqttMsg.getTopic(), jsonPrinter.print(encodedMsg));
+ extIntegrationInterface.processMqttMessage(mqttMsg.getTopic(), (FlowReport) encodedMsg);
+ }catch(Exception e1) {
+
+ try {
+ //not a plume_stats report and not network_metadata report, attempt to deserialize as WCStatsReport
+ encodedMsg = WCStatsReport.parseFrom(payload);
+ MQTT_LOG.debug("topic = {} IpDnsTelemetry = {}", mqttMsg.getTopic(), jsonPrinter.print(encodedMsg));
+ extIntegrationInterface.processMqttMessage(mqttMsg.getTopic(), (WCStatsReport) encodedMsg);
+ }catch(Exception e2) {
+ String msgStr = new String(mqttMsg.getPayload(), utf8);
+ MQTT_LOG.debug("topic = {} message = {}", mqttMsg.getTopic(), msgStr);
+ }
+ }
+ }
+
+ }
+
+ } catch(Exception e) {
+ LOG.error("Exception in MQTT receiver", e);
+ } finally {
+ try {
+ if(connection!=null) {
+ connection.disconnect();
+ }
+ } catch(Exception e1) {
+ //do nothing
+ }
+ }
+ }
+
+ };
+
+ Thread mqttClientThread = new Thread(mqttClientRunnable, "mqttClientThread");
+ mqttClientThread.setDaemon(true);
+ mqttClientThread.start();
+
+ }
+
+
+ @Override
+ public void onApplicationEvent(ContextClosedEvent event) {
+ LOG.debug("Processing ContextClosedEvent event");
+ keepReconnecting = false;
+ mqttClientThread.interrupt();
+ }
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/ConnectusOvsdbClient.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/ConnectusOvsdbClient.java
new file mode 100644
index 0000000..f075578
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/ConnectusOvsdbClient.java
@@ -0,0 +1,162 @@
+package ai.connectus.opensync.ovsdb;
+
+import java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.PostConstruct;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.vmware.ovsdb.callback.ConnectionCallback;
+import com.vmware.ovsdb.service.OvsdbClient;
+import com.vmware.ovsdb.service.OvsdbPassiveConnectionListener;
+
+import ai.connectus.opensync.external.integration.OpensyncExternalIntegrationInterface;
+import ai.connectus.opensync.external.integration.models.OpensyncAPConfig;
+import ai.connectus.opensync.ovsdb.dao.OvsdbDao;
+import ai.connectus.opensync.ovsdb.dao.models.ConnectNodeInfo;
+import ai.connectus.opensync.util.SslUtil;
+import io.netty.handler.ssl.SslContext;
+
+@Component
+public class ConnectusOvsdbClient {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnectusOvsdbClient.class);
+
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.ovsdb.listenPort:6640}")
+ private int ovsdbListenPort;
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.manager.collectionIntervalSec.deviceStats:10}")
+ private long collectionIntervalSecDeviceStats;
+
+ @Autowired
+ private SslContext sslContext;
+
+ @Autowired
+ private OvsdbPassiveConnectionListener listener;
+
+ @Autowired
+ private OvsdbDao ovsdbDao;
+
+ @Autowired
+ private OpensyncExternalIntegrationInterface extIntegrationInterface;
+
+ private final ConcurrentHashMap connectedClients = new ConcurrentHashMap<>();
+
+ @PostConstruct
+ private void postCreate() {
+ listenForConnections();
+ }
+
+ public void listenForConnections() {
+
+ ConnectionCallback connectionCallback = new ConnectionCallback() {
+ public void connected(OvsdbClient ovsdbClient) {
+ String remoteHost = ovsdbClient.getConnectionInfo().getRemoteAddress().getHostAddress();
+ int localPort = ovsdbClient.getConnectionInfo().getLocalPort();
+ String subjectDn = null;
+ try {
+ subjectDn = ((X509Certificate) ovsdbClient.getConnectionInfo().getRemoteCertificate()).getSubjectDN().getName();
+
+ String clientCn = SslUtil.extractCN(subjectDn);
+ LOG.info("ovsdbClient connecting from {} on port {} clientCn {}", remoteHost, localPort, clientCn);
+
+ ConnectNodeInfo connectNodeInfo = processConnectRequest(ovsdbClient, clientCn);
+
+ //successfully connected - register it in our connectedClients table
+ //In Plume's environment clientCn is not unique that's why we are augmenting it with the serialNumber and using it as a key (equivalent of KDC unique qrCode)
+ String key = clientCn + "_" + connectNodeInfo.serialNumber;
+ ConnectusOvsdbClient.this.connectedClients.put(key, ovsdbClient);
+ extIntegrationInterface.apConnected(key);
+
+ LOG.info("ovsdbClient connected from {} on port {} key {} ", remoteHost, localPort, key);
+
+ LOG.info("ovsdbClient connectedClients = {}", ConnectusOvsdbClient.this.connectedClients.size());
+
+ } catch (Exception e) {
+ LOG.error("ovsdbClient error", e);
+ //something is wrong with the SSL
+ ovsdbClient.shutdown();
+ return;
+ }
+
+ }
+ public void disconnected(OvsdbClient ovsdbClient) {
+ String remoteHost = ovsdbClient.getConnectionInfo().getRemoteAddress().getHostAddress();
+ int localPort = ovsdbClient.getConnectionInfo().getLocalPort();
+ String subjectDn = null;
+ try {
+ subjectDn = ((X509Certificate) ovsdbClient.getConnectionInfo().getRemoteCertificate()).getSubjectDN().getName();
+ } catch (Exception e) {
+ //do nothing
+ }
+
+ String clientCn = SslUtil.extractCN(subjectDn);
+
+ //disconnected - deregister ovsdbClient from our connectedClients table
+ //unfortunately we only know clientCn at this point, but in Plume's environment they are not unique
+ //so we are doing a reverse lookup here, and then if we find the key we will remove the entry from the connectedClients.
+ String key = ConnectusOvsdbClient.this.connectedClients.searchEntries(1,
+ (Entry t) -> { return t.getValue().equals(ovsdbClient) ? t.getKey() : null ;}
+ );
+
+ if(key!=null) {
+ ConnectusOvsdbClient.this.connectedClients.remove(key);
+ extIntegrationInterface.apDisconnected(key);
+ }
+
+ ovsdbClient.shutdown();
+
+ LOG.info("ovsdbClient disconnected from {} on port {} clientCn {} key {} ", remoteHost, localPort, clientCn, key);
+ LOG.info("ovsdbClient connectedClients = {}", ConnectusOvsdbClient.this.connectedClients.size());
+ }
+ };
+
+ listener.startListeningWithSsl(ovsdbListenPort, sslContext, connectionCallback).join();
+
+ LOG.debug("manager waiting for connection on port {}...", ovsdbListenPort);
+ }
+
+ private ConnectNodeInfo processConnectRequest(OvsdbClient ovsdbClient, String clientCn) {
+
+ LOG.debug("Starting Client connect");
+ ConnectNodeInfo connectNodeInfo = ovsdbDao.getConnectNodeInfo(ovsdbClient);
+ connectNodeInfo = ovsdbDao.updateConnectNodeInfoOnConnect(ovsdbClient, connectNodeInfo);
+
+ String apId = clientCn + "_" + connectNodeInfo.serialNumber;
+ OpensyncAPConfig opensyncAPConfig = extIntegrationInterface.getApConfig(apId);
+
+ ovsdbDao.configureStats(ovsdbClient);
+
+ //Check if device stats is configured in Wifi_Stats_Config table, provision it if needed
+ if(ovsdbDao.getDeviceStatsReportingInterval(ovsdbClient) != collectionIntervalSecDeviceStats) {
+ ovsdbDao.updateDeviceStatsReportingInterval(ovsdbClient, collectionIntervalSecDeviceStats);
+ }
+
+ ovsdbDao.removeOnboardingSsids(ovsdbClient);
+
+ if(opensyncAPConfig!=null) {
+ ovsdbDao.configureWifiRadios(ovsdbClient, opensyncAPConfig.getRadioConfig());
+ ovsdbDao.configureSsids(ovsdbClient, opensyncAPConfig.getSsidConfigs());
+ }
+
+ ovsdbDao.provisionBridgePortInterface(ovsdbClient);
+
+ ovsdbDao.configureWifiInet(ovsdbClient);
+
+ LOG.debug("Client connect Done");
+ return connectNodeInfo;
+ }
+
+ public Set getConnectedClientIds(){
+ return new HashSet<>(connectedClients.keySet());
+ }
+
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/ConnectusOvsdbRedirector.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/ConnectusOvsdbRedirector.java
new file mode 100644
index 0000000..694ab74
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/ConnectusOvsdbRedirector.java
@@ -0,0 +1,84 @@
+package ai.connectus.opensync.ovsdb;
+
+import java.security.cert.X509Certificate;
+
+import javax.annotation.PostConstruct;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.vmware.ovsdb.callback.ConnectionCallback;
+import com.vmware.ovsdb.service.OvsdbClient;
+import com.vmware.ovsdb.service.OvsdbPassiveConnectionListener;
+
+import ai.connectus.opensync.ovsdb.dao.OvsdbDao;
+import ai.connectus.opensync.util.SslUtil;
+import io.netty.handler.ssl.SslContext;
+
+@Component
+public class ConnectusOvsdbRedirector {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnectusOvsdbRedirector.class);
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.ovsdb.redirector.listenPort:6643}")
+ private int ovsdbRedirectorListenPort;
+
+ @Autowired
+ private SslContext sslContext;
+
+ @Autowired
+ private OvsdbDao ovsdbDao;
+
+ @Autowired
+ private OvsdbPassiveConnectionListener listener;
+
+ @PostConstruct
+ private void postCreate() {
+ listenForConnections();
+ }
+
+ public void listenForConnections() {
+
+ ConnectionCallback connectionCallback = new ConnectionCallback() {
+ public void connected(OvsdbClient ovsdbClient) {
+ String remoteHost = ovsdbClient.getConnectionInfo().getRemoteAddress().getHostAddress();
+ int localPort = ovsdbClient.getConnectionInfo().getLocalPort();
+ String subjectDn = null;
+ try {
+ subjectDn = ((X509Certificate) ovsdbClient.getConnectionInfo().getRemoteCertificate()).getSubjectDN().getName();
+
+ String clientCn = SslUtil.extractCN(subjectDn);
+ LOG.info("ovsdbClient redirector connected from {} on port {} clientCn {}", remoteHost, localPort, clientCn);
+ ovsdbDao.performRedirect(ovsdbClient, clientCn);
+
+ } catch (Exception e) {
+ //something is wrong with the SSL or with the redirect
+ ovsdbClient.shutdown();
+ return;
+ }
+ }
+
+ public void disconnected(OvsdbClient ovsdbClient) {
+ String remoteHost = ovsdbClient.getConnectionInfo().getRemoteAddress().getHostAddress();
+ int localPort = ovsdbClient.getConnectionInfo().getLocalPort();
+ String subjectDn = null;
+ try {
+ subjectDn = ((X509Certificate) ovsdbClient.getConnectionInfo().getRemoteCertificate()).getSubjectDN().getName();
+ } catch (Exception e) {
+ //do nothing
+ }
+ String clientCn = SslUtil.extractCN(subjectDn);
+ LOG.info("ovsdbClient redirector disconnected from {} on port {} clientCn {}", remoteHost, localPort, clientCn);
+ ovsdbClient.shutdown();
+ }
+ };
+
+ listener.startListeningWithSsl(ovsdbRedirectorListenPort, sslContext, connectionCallback).join();
+
+ LOG.debug("redirector waiting for connection on port {} ...", ovsdbRedirectorListenPort);
+
+ }
+
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/NettySslContextConfig.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/NettySslContextConfig.java
new file mode 100644
index 0000000..ea9f4e0
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/NettySslContextConfig.java
@@ -0,0 +1,101 @@
+package ai.connectus.opensync.ovsdb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.net.ssl.TrustManagerFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+
+@Configuration
+public class NettySslContextConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NettySslContextConfig.class);
+
+ @Bean(name="NettySslContextServer")
+ public SslContext nettySslContextServer(
+ @Value("${connectus.ovsdb.trustStore:/Users/dtop/Documents/certs_from_device/truststore.jks}")
+ String trustStoreFileName,
+
+ @Value("${connectus.ovsdb.keyStore:/Users/dtop/Documents/certs_from_device/server.p12}")
+ String keyFileName,
+
+ @Value("${connectus.ovsdb.keyStorePassword:mypassword}")
+ String keyStorePassword
+ ){
+ File trustStoreFile = new File(trustStoreFileName);
+ File keyFile = new File(keyFileName);
+
+ SslContext sslContext = null;
+
+ try {
+ char[] pwd = keyStorePassword.toCharArray();
+
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ try(InputStream is = new FileInputStream(keyFile)){
+ ks.load(is, pwd);
+ }
+
+ for(String alias: Collections.list(ks.aliases())) {
+ LOG.debug("Key Alias: {}", alias);
+ }
+
+ PrivateKey key = (PrivateKey) ks.getKey("1", pwd);
+ Certificate[] chain = ks.getCertificateChain("1");
+ X509Certificate[] keyCertChain = new X509Certificate[chain.length];
+ int i=0;
+ for(Certificate cert : chain) {
+ keyCertChain[i] = (X509Certificate) cert;
+ i++;
+ }
+
+ String keyPassword = null;
+ SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(key, keyPassword, keyCertChain );
+
+ KeyStore trustKs = KeyStore.getInstance("JKS");
+ try(InputStream is = new FileInputStream(trustStoreFile)){
+ trustKs.load(is, pwd);
+ }
+
+ List trustChain = new ArrayList<>();
+
+ for(String alias: Collections.list(trustKs.aliases())) {
+ LOG.debug("Trust Alias: {}", alias);
+ X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
+ trustChain.add(cert);
+ }
+
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+ tmf.init(trustKs);
+ sslContextBuilder.trustManager(tmf);
+
+ sslContext = sslContextBuilder.build();
+ LOG.debug("Built ssl context");
+ } catch (KeyStoreException|CertificateException|NoSuchAlgorithmException|IOException|UnrecoverableEntryException e) {
+ throw new RuntimeException(e);
+ }
+
+ return sslContext;
+ }
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/OvsdbListenerConfig.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/OvsdbListenerConfig.java
new file mode 100644
index 0000000..482a94d
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/OvsdbListenerConfig.java
@@ -0,0 +1,28 @@
+package ai.connectus.opensync.ovsdb;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.vmware.ovsdb.service.OvsdbPassiveConnectionListener;
+import com.vmware.ovsdb.service.impl.OvsdbPassiveConnectionListenerImpl;
+
+@Configuration
+public class OvsdbListenerConfig {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OvsdbListenerConfig.class);
+
+ @Bean
+ public OvsdbPassiveConnectionListener ovsdbPassiveConnectionListener(
+ @org.springframework.beans.factory.annotation.Value("${connectus.ovsdb.listener.threadPoolSize:10}")
+ int threadPoolSize) {
+ LOG.debug("Configuring OvsdbPassiveConnectionListener with thread pool size {}", threadPoolSize);
+ ScheduledExecutorService executorService = Executors.newScheduledThreadPool(threadPoolSize);
+ OvsdbPassiveConnectionListener listener = new OvsdbPassiveConnectionListenerImpl(executorService);
+ return listener;
+ }
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/OvsdbDao.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/OvsdbDao.java
new file mode 100644
index 0000000..4c0f137
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/OvsdbDao.java
@@ -0,0 +1,1402 @@
+package ai.connectus.opensync.ovsdb.dao;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.vmware.ovsdb.exception.OvsdbClientException;
+import com.vmware.ovsdb.protocol.operation.Delete;
+import com.vmware.ovsdb.protocol.operation.Insert;
+import com.vmware.ovsdb.protocol.operation.Operation;
+import com.vmware.ovsdb.protocol.operation.Select;
+import com.vmware.ovsdb.protocol.operation.Update;
+import com.vmware.ovsdb.protocol.operation.notation.Atom;
+import com.vmware.ovsdb.protocol.operation.notation.Condition;
+import com.vmware.ovsdb.protocol.operation.notation.Function;
+import com.vmware.ovsdb.protocol.operation.notation.Row;
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+import com.vmware.ovsdb.protocol.operation.notation.Value;
+import com.vmware.ovsdb.protocol.operation.result.InsertResult;
+import com.vmware.ovsdb.protocol.operation.result.OperationResult;
+import com.vmware.ovsdb.protocol.operation.result.SelectResult;
+import com.vmware.ovsdb.service.OvsdbClient;
+import com.whizcontrol.core.model.equipment.RadioType;
+
+import ai.connectus.opensync.external.integration.models.OpensyncAPRadioConfig;
+import ai.connectus.opensync.external.integration.models.OpensyncAPSsidConfig;
+import ai.connectus.opensync.ovsdb.dao.models.BridgeInfo;
+import ai.connectus.opensync.ovsdb.dao.models.ConnectNodeInfo;
+import ai.connectus.opensync.ovsdb.dao.models.InterfaceInfo;
+import ai.connectus.opensync.ovsdb.dao.models.PortInfo;
+import ai.connectus.opensync.ovsdb.dao.models.WifiInetConfigInfo;
+import ai.connectus.opensync.ovsdb.dao.models.WifiRadioConfigInfo;
+import ai.connectus.opensync.ovsdb.dao.models.WifiStatsConfigInfo;
+import ai.connectus.opensync.ovsdb.dao.models.WifiVifConfigInfo;
+
+@Component
+public class OvsdbDao {
+ private static final Logger LOG = LoggerFactory.getLogger(OvsdbDao.class);
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.ovsdb.managerAddr:3.88.149.10}")
+ private String managerIpAddr;
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.ovsdb.listenPort:6640}")
+ private int ovsdbListenPort;
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.mqttBroker.address:testportal.123wlan.com}")
+ private String mqttBrokerAddress;
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.mqttBroker.listenPort:1883}")
+ private int mqttBrokerListenPort;
+
+ @org.springframework.beans.factory.annotation.Value("${connectus.ovsdb.timeoutSec:30}")
+ private int ovsdbTimeoutSec;
+
+ public static final String ovsdbName = "Open_vSwitch";
+ public static final String awlanNodeDbTable = "AWLAN_Node";
+ public static final String wifiStatsConfigDbTable = "Wifi_Stats_Config";
+
+ public static final String interfaceDbTable = "Interface";
+ public static final String portDbTable = "Port";
+ public static final String bridgeDbTable = "Bridge";
+ public static final String wifiRadioConfigDbTable = "Wifi_Radio_Config";
+ public static final String wifiVifConfigDbTable = "Wifi_VIF_Config";
+ public static final String wifiInetConfigDbTable = "Wifi_Inet_Config";
+
+
+
+ //
+ //Note: When talking to OVSDB always use future.get(X, TimeUnit.SECONDS); - to prevent DOS attacks with misbehaving clients
+ //
+
+ public ConnectNodeInfo getConnectNodeInfo(OvsdbClient ovsdbClient) {
+ ConnectNodeInfo ret = new ConnectNodeInfo();
+
+ try {
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("mqtt_settings");
+ columns.add("redirector_addr");
+ columns.add("manager_addr");
+ columns.add("sku_number");
+ columns.add("serial_number");
+
+ operations.add(new Select(awlanNodeDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Select from {}:", awlanNodeDbTable);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ Row row = null;
+ if (result != null && result.length > 0 && !((SelectResult) result[0]).getRows().isEmpty()) {
+ row = ((SelectResult)result[0]).getRows().iterator().next();
+ }
+
+ ret.mqttSettings = (row!=null)?row.getMapColumn("mqtt_settings"):null;
+ ret.redirectorAddr = (row!=null)?row.getStringColumn("redirector_addr"):null;
+ ret.managerAddr = (row!=null)?row.getStringColumn("manager_addr"):null;
+
+ ret.skuNumber = getSingleValueFromSet(row, "sku_number");
+ ret.serialNumber = getSingleValueFromSet(row, "serial_number");
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public ConnectNodeInfo updateConnectNodeInfoOnConnect(OvsdbClient ovsdbClient, ConnectNodeInfo incomingConnectNodeInfo) {
+ ConnectNodeInfo ret = incomingConnectNodeInfo.clone();
+
+ try {
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+
+ //set device_mode = cloud - plume's APs do not use it
+ //updateColumns.put("device_mode", new Atom("cloud") );
+
+ //update sku_number if it was empty
+ if(ret.skuNumber == null || ret.skuNumber.isEmpty()) {
+ ret.skuNumber = "connectus.ai_"+ ret.serialNumber;
+ updateColumns.put("sku_number", new Atom(ret.skuNumber) );
+ }
+
+ //Configure the MQTT connection
+ //ovsh u AWLAN_Node mqtt_settings:ins:'["map",[["broker","testportal.123wlan.com"],["topics","/ap/dev-ap-0300/opensync"],["qos","0"],["port","1883"],["remote_log","1"]]]'
+ Map newMqttSettings = new HashMap<>();
+ newMqttSettings.put("broker", mqttBrokerAddress);
+ newMqttSettings.put("topics", "/ap/"+ret.serialNumber+"/opensync");
+ newMqttSettings.put("port", ""+mqttBrokerListenPort);
+ newMqttSettings.put("compress","zlib");
+ newMqttSettings.put("qos", "0");
+ newMqttSettings.put("remote_log", "1");
+
+ if(ret.mqttSettings == null || !ret.mqttSettings.equals(newMqttSettings)) {
+ @SuppressWarnings("unchecked")
+ com.vmware.ovsdb.protocol.operation.notation.Map mgttSettings = com.vmware.ovsdb.protocol.operation.notation.Map.of(newMqttSettings);
+ ret.mqttSettings = newMqttSettings;
+ updateColumns.put("mqtt_settings", mgttSettings);
+ }
+
+ if(!updateColumns.isEmpty()) {
+ Row row = new Row(updateColumns );
+ operations.add(new Update(awlanNodeDbTable, row ));
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Updated {}:", awlanNodeDbTable);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+ }
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+
+ /**
+ * @param ovsdbClient
+ * @return value of reporting_interval column for the stats_type=device from the Wifi_Stats_Config table. If value is not provisioned then return -1.
+ */
+ public long getDeviceStatsReportingInterval(OvsdbClient ovsdbClient) {
+ long ret = -1;
+ try {
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+
+ columns.add("reporting_interval");
+ columns.add("stats_type");
+ columns.add("radio_type");
+
+ conditions.add(new Condition("stats_type", Function.EQUALS, new Atom<>("device") ));
+
+ operations.add(new Select(wifiStatsConfigDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Select from {}:", wifiStatsConfigDbTable);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ Row row = null;
+ if (result != null && result.length > 0 && !((SelectResult) result[0]).getRows().isEmpty()) {
+ row = ((SelectResult)result[0]).getRows().iterator().next();
+ ret = row.getIntegerColumn("reporting_interval");
+ LOG.info("Stats collection for stats_type=device is already configured with reporting_interval = {}", ret);
+ }
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ /**
+ * @param ovsdbClient
+ * @param value of reporting_interval column for the stats_type=device from the Wifi_Stats_Config table. If value is not provisioned then return -1.
+ */
+ public void updateDeviceStatsReportingInterval(OvsdbClient ovsdbClient, long newValue) {
+ try {
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+
+ //turn on stats collection over MQTT: (reporting_interval is in seconds?)
+ //$ ovsh i Wifi_Stats_Config reporting_interval:=10 radio_type:="2.4G" stats_type:="device"
+
+ updateColumns.put("reporting_interval", new Atom(10) );
+ updateColumns.put("radio_type", new Atom("2.4G") );
+ updateColumns.put("stats_type", new Atom("device") );
+
+ Row row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Updated {}:", wifiStatsConfigDbTable);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+
+ public void performRedirect(OvsdbClient ovsdbClient, String clientCn) {
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("manager_addr");
+ columns.add("sku_number");
+ columns.add("serial_number");
+ columns.add("model");
+ columns.add("firmware_version");
+
+ try {
+ LOG.debug("Starting Redirect");
+
+ operations.add(new Select(awlanNodeDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Select from AWLAN_Node:");
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ String skuNumber = null;
+ String serialNumber = null;
+ String model = null;
+ String firmwareVersion = null;
+
+ Row row = null;
+ if (result != null && result.length > 0 && !((SelectResult) result[0]).getRows().isEmpty()) {
+ row = ((SelectResult)result[0]).getRows().iterator().next();
+ }
+
+ firmwareVersion = (row!=null)?row.getStringColumn("firmware_version"):null;
+
+ skuNumber = getSingleValueFromSet(row, "sku_number");
+ serialNumber = getSingleValueFromSet(row, "serial_number");
+ model = getSingleValueFromSet(row, "model");
+
+ LOG.info("Redirecting AP Node: clientCn {} serialNumber {} model {} firmwareVersion {} skuNumber {}", clientCn, serialNumber, model, firmwareVersion, skuNumber);
+
+ //Update table AWLAN_Node - set manager_addr
+ operations.clear();
+ Map updateColumns = new HashMap<>();
+
+ updateColumns.put("manager_addr", new Atom("ssl:" + managerIpAddr + ":" + ovsdbListenPort) );
+
+ row = new Row(updateColumns );
+ operations.add(new Update(awlanNodeDbTable, row ));
+
+ fResult = ovsdbClient.transact(ovsdbName, operations);
+ result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Updated AWLAN_Node:");
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ LOG.debug("Redirect Done");
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error when redirecting AP Node", e);
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public T getSingleValueFromSet(Row row, String columnName){
+
+ Set set = (row!=null)?row.getSetColumn(columnName):null;
+ T ret = (set!=null && !set.isEmpty())? set.iterator().next(): null;
+
+ return ret;
+ }
+
+ public Map getProvisionedInterfaces(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("name");
+ columns.add("_uuid");
+ columns.add("ofport");
+ columns.add("mtu");
+ columns.add("ifindex");
+ columns.add("link_state");
+ columns.add("admin_state");
+
+ try {
+ LOG.debug("Retrieving Interfaces:");
+
+ operations.add(new Select(interfaceDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ InterfaceInfo interfaceInfo = new InterfaceInfo();
+ interfaceInfo.name = row.getStringColumn("name");
+ interfaceInfo.uuid = row.getUuidColumn("_uuid");
+ interfaceInfo.ofport = row.getIntegerColumn("ofport").intValue();
+ interfaceInfo.mtu = row.getIntegerColumn("mtu").intValue();
+ interfaceInfo.ifIndex = row.getIntegerColumn("ifindex").intValue();
+ interfaceInfo.linkState = row.getStringColumn("link_state");
+ interfaceInfo.adminState = row.getStringColumn("admin_state");
+
+ ret.put(interfaceInfo.name, interfaceInfo);
+ }
+
+ LOG.debug("Retrieved Interfaces: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedInterfaces", e);
+
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public Map getProvisionedPorts(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("name");
+ columns.add("_uuid");
+ columns.add("interfaces");
+
+ try {
+ LOG.debug("Retrieving Ports:");
+
+ operations.add(new Select(portDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ PortInfo portInfo = new PortInfo();
+ portInfo.name = row.getStringColumn("name");
+ portInfo.uuid = row.getUuidColumn("_uuid");
+ portInfo.interfaceUuids = row.getSetColumn("interfaces");
+
+ ret.put(portInfo.name, portInfo);
+ }
+
+ LOG.debug("Retrieved Ports: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedPorts", e);
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public Map getProvisionedBridges(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("name");
+ columns.add("_uuid");
+ columns.add("ports");
+
+ try {
+ LOG.debug("Retrieving Bridges:");
+
+ operations.add(new Select(bridgeDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ BridgeInfo bridgeInfo = new BridgeInfo();
+ bridgeInfo.name = row.getStringColumn("name");
+ bridgeInfo.uuid = row.getUuidColumn("_uuid");
+ bridgeInfo.portUuids = row.getSetColumn("ports");
+
+ ret.put(bridgeInfo.name, bridgeInfo);
+ }
+
+ LOG.debug("Retrieved Bridges: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedBridges", e);
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public Map getProvisionedWifiRadioConfigs(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+
+ columns.add("_uuid");
+ columns.add("if_name");
+
+ columns.add("channel");
+ columns.add("channel_mode");
+ columns.add("country");
+ columns.add("enabled");
+ columns.add("ht_mode");
+ columns.add("tx_power");
+ columns.add("vif_configs");
+ columns.add("freq_band");
+ columns.add("hw_config");
+
+ try {
+ LOG.debug("Retrieving WifiRadioConfig:");
+
+ operations.add(new Select(wifiRadioConfigDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ WifiRadioConfigInfo wifiRadioConfigInfo = new WifiRadioConfigInfo();
+ wifiRadioConfigInfo.uuid = row.getUuidColumn("_uuid");
+ wifiRadioConfigInfo.ifName = row.getStringColumn("if_name");
+ Long channelTmp = getSingleValueFromSet(row, "channel");
+ if (channelTmp==null) {
+ channelTmp = -1L;
+ }
+ wifiRadioConfigInfo.channel = channelTmp.intValue();
+ wifiRadioConfigInfo.channelMode = row.getStringColumn("channel_mode");
+ wifiRadioConfigInfo.country = getSingleValueFromSet(row, "country");
+ Boolean tmp = getSingleValueFromSet(row, "enabled");
+ wifiRadioConfigInfo.enabled = tmp!=null?tmp:false;
+ wifiRadioConfigInfo.htMode = getSingleValueFromSet(row, "ht_mode");
+ wifiRadioConfigInfo.txPower = getSingleValueFromSet(row, "txPower");
+ wifiRadioConfigInfo.vifConfigUuids = row.getSetColumn("vif_configs");
+ wifiRadioConfigInfo.freqBand = row.getStringColumn("freq_band");
+ wifiRadioConfigInfo.hwConfig = row.getMapColumn("hw_config");
+
+
+ ret.put(wifiRadioConfigInfo.ifName, wifiRadioConfigInfo);
+ }
+
+ LOG.debug("Retrieved WifiRadioConfig: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedWifiRadioConfigs", e);
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public Map getProvisionedWifiVifConfigs(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("bridge");
+ columns.add("_uuid");
+ columns.add("btm");
+ columns.add("enabled");
+ columns.add("ft_psk");
+ columns.add("group_rekey");
+ columns.add("if_name");
+ columns.add("mode");
+ columns.add("rrm");
+ columns.add("ssid");
+ columns.add("ssid_broadcast");
+ columns.add("uapsd_enable");
+ columns.add("vif_radio_idx");
+ columns.add("security");
+
+ try {
+ LOG.debug("Retrieving WifiVifConfig:");
+
+ operations.add(new Select(wifiVifConfigDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ WifiVifConfigInfo wifiVifConfigInfo = new WifiVifConfigInfo();
+ wifiVifConfigInfo.bridge = row.getStringColumn("bridge");
+ wifiVifConfigInfo.uuid = row.getUuidColumn("_uuid");
+ wifiVifConfigInfo.btm = row.getIntegerColumn("btm").intValue();
+ wifiVifConfigInfo.enabled = row.getBooleanColumn("enabled");
+ wifiVifConfigInfo.ftPsk = row.getIntegerColumn("ft_psk").intValue();
+ wifiVifConfigInfo.groupRekey = row.getIntegerColumn("group_rekey").intValue();
+ wifiVifConfigInfo.ifName = row.getStringColumn("if_name");
+ wifiVifConfigInfo.mode = row.getStringColumn("mode");
+ wifiVifConfigInfo.rrm = row.getIntegerColumn("rrm").intValue();
+ wifiVifConfigInfo.ssid = row.getStringColumn("ssid");
+ wifiVifConfigInfo.ssidBroadcast = row.getStringColumn("ssid_broadcast");
+ wifiVifConfigInfo.uapsdEnable = row.getBooleanColumn("uapsd_enable");
+ wifiVifConfigInfo.vifRadioIdx = row.getIntegerColumn("vif_radio_idx").intValue();
+ wifiVifConfigInfo.security = row.getMapColumn("security");
+
+ ret.put(wifiVifConfigInfo.ifName + '_' + wifiVifConfigInfo.ssid, wifiVifConfigInfo);
+ }
+
+ LOG.debug("Retrieved WifiVifConfigs: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedWifiVifConfigs", e);
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public Map getProvisionedWifiInetConfigs(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("NAT");
+ columns.add("_uuid");
+ columns.add("enabled");
+ columns.add("if_name");
+ columns.add("if_type");
+ columns.add("ip_assign_scheme");
+ columns.add("network");
+
+ try {
+ LOG.debug("Retrieving WifiInetConfig:");
+
+ operations.add(new Select(wifiInetConfigDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ WifiInetConfigInfo wifiInetConfigInfo = new WifiInetConfigInfo();
+ Boolean natTmp = getSingleValueFromSet(row, "NAT");
+ wifiInetConfigInfo.nat = natTmp!=null?natTmp:false;
+
+ wifiInetConfigInfo.uuid = row.getUuidColumn("_uuid");
+ wifiInetConfigInfo.enabled = row.getBooleanColumn("enabled");
+ wifiInetConfigInfo.ifName = row.getStringColumn("if_name");
+ wifiInetConfigInfo.ifType = row.getStringColumn("if_type");
+ wifiInetConfigInfo.ipAssignScheme = row.getStringColumn("ip_assign_scheme");
+ wifiInetConfigInfo.network = row.getBooleanColumn("network");
+
+ ret.put(wifiInetConfigInfo.ifName, wifiInetConfigInfo);
+ }
+
+ LOG.debug("Retrieved WifiInetConfigs: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedWifiInetConfigs", e);
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public Map getProvisionedWifiStatsConfigs(OvsdbClient ovsdbClient){
+ Map ret = new HashMap<>();
+
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ List columns = new ArrayList<>();
+ columns.add("channel_list");
+ columns.add("radio_type");
+ columns.add("reporting_interval");
+ columns.add("sampling_interval");
+ columns.add("stats_type");
+ columns.add("survey_interval_ms");
+ columns.add("survey_type");
+ columns.add("threshold");
+ columns.add("_uuid");
+
+ try {
+ LOG.debug("Retrieving WifiStatsConfigs:");
+
+ operations.add(new Select(wifiStatsConfigDbTable, conditions , columns ));
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ for(Row row :((SelectResult)result[0]).getRows()){
+
+ WifiStatsConfigInfo wifiStatsConfigInfo = new WifiStatsConfigInfo();
+
+ wifiStatsConfigInfo.channelList = row.getSetColumn("channel_list");
+ wifiStatsConfigInfo.radioType = row.getStringColumn("radio_type");
+ wifiStatsConfigInfo.reportingInterval = row.getIntegerColumn("reporting_interval").intValue();
+ wifiStatsConfigInfo.samplingInterval = row.getIntegerColumn("sampling_interval").intValue();
+ wifiStatsConfigInfo.statsType = row.getStringColumn("stats_type");
+ wifiStatsConfigInfo.surveyType = getSingleValueFromSet(row, "survey_type");
+ Long tmp = getSingleValueFromSet(row, "survey_interval_ms");
+ wifiStatsConfigInfo.surveyIntervalMs = tmp!=null? tmp.intValue(): 0;
+ wifiStatsConfigInfo.threshold = row.getMapColumn("threshold");
+ wifiStatsConfigInfo.uuid = row.getUuidColumn("_uuid");
+
+ ret.put(wifiStatsConfigInfo.radioType + "_" + wifiStatsConfigInfo.statsType + "_" + wifiStatsConfigInfo.surveyType, wifiStatsConfigInfo);
+ }
+
+ LOG.debug("Retrieved WifiStatsConfigs: {}", ret);
+
+ } catch (ExecutionException | InterruptedException | OvsdbClientException | TimeoutException e) {
+ LOG.error("Error in getProvisionedWifiStatsConfigs", e);
+
+ throw new RuntimeException(e);
+ }
+
+ return ret;
+ }
+
+ public void provisionSingleBridgePortInterface(OvsdbClient ovsdbClient, String interfaceName, String bridgeName, int ifIndex,
+ int ofport, Map provisionedInterfaces, Map provisionedPorts,
+ Map provisionedBridges)
+ throws OvsdbClientException, TimeoutException, ExecutionException, InterruptedException {
+
+ if(!provisionedInterfaces.containsKey(interfaceName)) {
+ //Create this interface and link it to the port and the bridge
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+ List conditions = new ArrayList<>();
+
+
+ updateColumns.put("name", new Atom(interfaceName) );
+ updateColumns.put("admin_state", new Atom("up") );
+ updateColumns.put("link_state", new Atom("up") );
+ updateColumns.put("ifindex", new Atom(ifIndex) );
+ updateColumns.put("mtu", new Atom(1500) );
+ updateColumns.put("ofport", new Atom(ofport) );
+ Uuid interfaceUuid = null;
+
+ Row row = new Row(updateColumns );
+ operations.add(new Insert(interfaceDbTable, row ));
+
+ {
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Provisioned Interface for {}", interfaceName);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ if(res instanceof InsertResult) {
+ interfaceUuid = ((InsertResult) res).getUuid();
+ }
+ }
+ }
+
+ if (interfaceUuid == null) {
+ throw new IllegalStateException("Interface entry was not created successfully");
+ }
+
+ Uuid portUuid = null;
+ operations = new ArrayList<>();
+ //link the interface to the port, create port if necessary
+ if(!provisionedPorts.containsKey(interfaceName)) {
+ //need to create port
+ updateColumns = new HashMap<>();
+
+ //portUuid = new Uuid(new UUID(System.currentTimeMillis(), System.nanoTime())) ;
+ updateColumns.put("name", new Atom(interfaceName) );
+ //updateColumns.put("_uuid", new Atom(portUuid));
+
+ Set portInterfacesSet = new HashSet<>();
+ portInterfacesSet.add(interfaceUuid);
+ com.vmware.ovsdb.protocol.operation.notation.Set portInterfaces = com.vmware.ovsdb.protocol.operation.notation.Set.of(portInterfacesSet);
+ updateColumns.put("interfaces", portInterfaces );
+
+ row = new Row(updateColumns);
+ operations.add(new Insert(portDbTable, row ));
+
+ {
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Provisioned Port for {}", interfaceName);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ if(res instanceof InsertResult) {
+ portUuid = ((InsertResult) res).getUuid();
+ }
+ }
+ }
+
+ } else {
+ //need to update port
+ PortInfo existingPort = provisionedPorts.get(interfaceName);
+ portUuid = existingPort.uuid;
+
+ conditions = new ArrayList<>();
+ updateColumns = new HashMap<>();
+
+ conditions.add(new Condition("name", Function.EQUALS, new Atom<>(interfaceName) ));
+
+ Set portInterfacesSet = new HashSet<>(existingPort.interfaceUuids);
+ portInterfacesSet.add(interfaceUuid);
+ com.vmware.ovsdb.protocol.operation.notation.Set portInterfaces = com.vmware.ovsdb.protocol.operation.notation.Set.of(portInterfacesSet);
+ updateColumns.put("interfaces", portInterfaces );
+
+ row = new Row(updateColumns);
+ operations.add(new Update(portDbTable, row ));
+
+ {
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Updated Port for {}", interfaceName);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ }
+
+
+ if (portUuid == null) {
+ throw new IllegalStateException("Port entry was not created successfully");
+ }
+
+
+ operations = new ArrayList<>();
+
+ //link the port to the bridge
+ if(provisionedBridges.containsKey(bridgeName)) {
+ BridgeInfo existingBridge = provisionedBridges.get(brHome);
+
+ conditions = new ArrayList<>();
+ updateColumns = new HashMap<>();
+
+ conditions.add(new Condition("name", Function.EQUALS, new Atom<>(bridgeName) ));
+
+ Set bridgePortsSet = new HashSet<>(existingBridge.portUuids);
+ bridgePortsSet.add(portUuid);
+ com.vmware.ovsdb.protocol.operation.notation.Set bridgePorts = com.vmware.ovsdb.protocol.operation.notation.Set.of(bridgePortsSet);
+ updateColumns.put("ports", bridgePorts );
+
+ row = new Row(updateColumns);
+ operations.add(new Update(bridgeDbTable, row ));
+
+ } else {
+ LOG.warn("provisionedBridges does not have bridge {} - {} - port will be dangling", bridgeName, provisionedBridges.keySet());
+ }
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Finished provisioning Interface/port/bridge for {} / {}", interfaceName, bridgeName);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ }
+ }
+
+ public static final String homeAp24 = "home-ap-24";
+ public static final String homeApL50 = "home-ap-l50";
+ public static final String brHome = "br-home";
+ public static final String brWan = "br-wan";
+
+ public void provisionBridgePortInterface(OvsdbClient ovsdbClient) {
+ try {
+ Map provisionedInterfaces = getProvisionedInterfaces(ovsdbClient);
+ LOG.debug("Existing Interfaces: {}", provisionedInterfaces.keySet());
+
+ Map provisionedPorts = getProvisionedPorts(ovsdbClient);
+ LOG.debug("Existing Ports: {}", provisionedPorts.keySet());
+
+ Map provisionedBridges = getProvisionedBridges(ovsdbClient);
+ LOG.debug("Existing Bridges: {}", provisionedBridges.keySet());
+
+ provisionSingleBridgePortInterface(ovsdbClient, homeApL50, brHome, 30, 1, provisionedInterfaces, provisionedPorts, provisionedBridges);
+ provisionSingleBridgePortInterface(ovsdbClient, homeAp24, brHome, 31, 2, provisionedInterfaces, provisionedPorts, provisionedBridges);
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ LOG.error("Error in provisionBridgePortInterface", e);
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void removeOnboardingSsids(OvsdbClient ovsdbClient) {
+ try {
+ List operations = new ArrayList<>();
+ List conditions = new ArrayList<>();
+ conditions.add(new Condition("ssid", Function.EQUALS, new Atom<>("opensync.onboard") ));
+
+ operations.add(new Delete(wifiVifConfigDbTable, conditions ));
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Removed onboarding SSIDs from {}:", wifiVifConfigDbTable);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ LOG.error("Error in removeOnboardingSsids", e);
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void configureWifiRadios(OvsdbClient ovsdbClient, OpensyncAPRadioConfig opensyncAPRadioConfig) {
+ Map provisionedWifiRadios = getProvisionedWifiRadioConfigs(ovsdbClient);
+ LOG.debug("Existing WifiRadioConfigs: {}", provisionedWifiRadios.keySet());
+
+ try {
+ String country = opensyncAPRadioConfig.getCountry();
+ String configName = "wifi0";
+ int channel = opensyncAPRadioConfig.getRadioChannel24G();
+ Map hwConfig = new HashMap<>();
+ configureWifiRadios(ovsdbClient, configName, provisionedWifiRadios, channel, hwConfig, country);
+
+ configName = "wifi1";
+ channel = opensyncAPRadioConfig.getRadioChannel5LG();
+ hwConfig = new HashMap<>();
+ hwConfig.put("dfs_enable", "1");
+ hwConfig.put("dfs_ignorecac", "0");
+ hwConfig.put("dfs_usenol", "1");
+
+ configureWifiRadios(ovsdbClient, configName, provisionedWifiRadios, channel, hwConfig, country);
+
+ configName = "wifi2";
+ channel = opensyncAPRadioConfig.getRadioChannel5HG();
+ hwConfig = new HashMap<>();
+ hwConfig.put("dfs_enable", "1");
+ hwConfig.put("dfs_ignorecac", "0");
+ hwConfig.put("dfs_usenol", "1");
+
+ configureWifiRadios(ovsdbClient, configName, provisionedWifiRadios, channel, hwConfig, country);
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ LOG.error("Error in configureWifiRadios", e);
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void configureWifiRadios(OvsdbClient ovsdbClient, String configName,
+ Map provisionedWifiRadios, int channel, Map hwConfig, String country )
+ throws OvsdbClientException, TimeoutException, ExecutionException, InterruptedException {
+
+ WifiRadioConfigInfo existingConfig = provisionedWifiRadios.get(configName);
+
+ if(existingConfig==null) {
+ LOG.warn("There is no WifiRadioConfig {}", configName);
+ return;
+ }
+
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+ List conditions = new ArrayList<>();
+ conditions.add(new Condition("if_name", Function.EQUALS, new Atom<>(configName) ));
+
+ updateColumns.put("channel", new Atom(channel) );
+ updateColumns.put("country", new Atom<>(country) );
+ @SuppressWarnings("unchecked")
+ com.vmware.ovsdb.protocol.operation.notation.Map hwConfigMap = com.vmware.ovsdb.protocol.operation.notation.Map.of(hwConfig);
+ updateColumns.put("hw_config", hwConfigMap);
+
+ Row row = new Row(updateColumns );
+ operations.add(new Update(wifiRadioConfigDbTable, conditions, row ));
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Provisioned channel {} for {}", channel, configName);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ public void configureSingleSsid(OvsdbClient ovsdbClient, String bridge, String ifName, String ssid, boolean ssidBroadcast, Map security, Map provisionedWifiRadioConfigs, String radioIfName) {
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+
+ try {
+ ///usr/plume/tools/ovsh i Wifi_VIF_Config
+ // bridge:=br-home btm:=1 enabled:=true ft_psk:=0 group_rekey:=86400
+ // if_name:=home-ap-24 mode:=ap rrm:=1 ssid:=ConnectUS-Plume ssid_broadcast:=enabled
+ // uapsd_enable:=true vif_radio_idx:=2 security:='["map",[["encryption","WPA-PSK"],["key","12345678"],["mode","2"]]]'
+
+ updateColumns.put("bridge", new Atom<>(bridge) );
+ updateColumns.put("btm", new Atom<>(1) );
+ updateColumns.put("enabled", new Atom<>(true) );
+ updateColumns.put("ft_psk", new Atom<>(0) );
+ updateColumns.put("group_rekey", new Atom<>(86400) );
+ updateColumns.put("if_name", new Atom<>(ifName) );
+ updateColumns.put("mode", new Atom<>("ap") );
+ updateColumns.put("rrm", new Atom<>(1) );
+ updateColumns.put("ssid", new Atom<>(ssid) );
+ updateColumns.put("ssid_broadcast", new Atom<>(ssidBroadcast?"enabled":"disabled") );
+ updateColumns.put("uapsd_enable", new Atom<>(true) );
+ updateColumns.put("vif_radio_idx", new Atom<>(2) );
+
+ @SuppressWarnings("unchecked")
+ com.vmware.ovsdb.protocol.operation.notation.Map securityMap = com.vmware.ovsdb.protocol.operation.notation.Map.of(security);
+ updateColumns.put("security", securityMap);
+
+ Row row = new Row(updateColumns);
+ operations.add(new Insert(wifiVifConfigDbTable, row ));
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Provisioned SSID {} on {}", ssid, ifName);
+
+ Uuid vifConfigUuid = null;
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ if(res instanceof InsertResult) {
+ vifConfigUuid = ((InsertResult) res).getUuid();
+ }
+ }
+
+ if (vifConfigUuid == null) {
+ throw new IllegalStateException("Wifi_VIF_Config entry was not created successfully");
+ }
+
+ //update Wifi_Radio_Config here - add vifConfigUuid
+ ///usr/plume/tools/ovsh u Wifi_Radio_Config vif_configs:='["set",[["uuid","98e42897-b567-4186-84a6-4a4e38a51e9d"],["uuid","4314920e-c4e6-42a6-93e3-261142ed9adf"]]]' --where if_name==wifi0
+ updateColumns.clear();
+ operations.clear();
+
+ WifiRadioConfigInfo wifiRadioConfigInfo = provisionedWifiRadioConfigs.get(radioIfName);
+ if(wifiRadioConfigInfo == null) {
+ throw new IllegalStateException("missing Wifi_Radio_Config entry "+ radioIfName);
+ }
+
+ Set vifConfigsSet = new HashSet<>(wifiRadioConfigInfo.vifConfigUuids);
+ vifConfigsSet.add(vifConfigUuid);
+ com.vmware.ovsdb.protocol.operation.notation.Set vifConfigs = com.vmware.ovsdb.protocol.operation.notation.Set.of(vifConfigsSet);
+ updateColumns.put("vif_configs", vifConfigs );
+
+ List conditions = new ArrayList<>();
+ conditions.add(new Condition("if_name", Function.EQUALS, new Atom<>(radioIfName) ));
+
+ row = new Row(updateColumns);
+ operations.add(new Update(wifiRadioConfigDbTable, conditions, row ));
+
+ fResult = ovsdbClient.transact(ovsdbName, operations);
+ result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Updated WifiRadioConfig {} for SSID {}:", radioIfName, ssid);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+
+ LOG.info("Provisioned SSID {} on interface {} / {}", ssid, ifName, radioIfName);
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ LOG.error("Error in configureSingleSsid", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void configureSsids(OvsdbClient ovsdbClient, List ssidConfigs) {
+ if(ssidConfigs==null || ssidConfigs.isEmpty()) {
+ LOG.debug("No SSIDs to configure");
+ return;
+ }
+
+ Map provisionedWifiVifConfigs = getProvisionedWifiVifConfigs(ovsdbClient);
+ Map provisionedWifiRadioConfigs = getProvisionedWifiRadioConfigs(ovsdbClient);
+ LOG.debug("Existing WifiVifConfigs: {}", provisionedWifiVifConfigs.keySet());
+
+ for(OpensyncAPSsidConfig ssidCfg: ssidConfigs) {
+ String bridge = brHome;
+ String ifName = (ssidCfg.getRadioType() == RadioType.is2dot4GHz)?homeAp24:homeApL50;
+ String radioIfName = (ssidCfg.getRadioType() == RadioType.is2dot4GHz)?"wifi0":"wifi1";
+ String ssid = ssidCfg.getSsid();
+ boolean ssidBroadcast = ssidCfg.isBroadcast();
+ Map security = new HashMap<>();
+ security.put("encryption", ssidCfg.getEncryption());
+ security.put("key", ssidCfg.getKey());
+ security.put("mode", ssidCfg.getMode());
+
+ if(!provisionedWifiVifConfigs.containsKey(ifName+"_"+ssid)){
+ try {
+ configureSingleSsid(ovsdbClient, bridge, ifName, ssid, ssidBroadcast, security, provisionedWifiRadioConfigs, radioIfName);
+ } catch (IllegalStateException e) {
+ //could not provision this SSID, but still can go on
+ LOG.warn("could not provision SSID {} on {}", ssid, radioIfName);
+ }
+ }
+
+ }
+
+ }
+
+ public void configureWifiInet(OvsdbClient ovsdbClient, Map provisionedWifiInetConfigs, String ifName) {
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+
+ try {
+ ///usr/plume/tools/ovsh i Wifi_Inet_Config NAT:=false enabled:=true if_name:=home-ap-24 if_type:=vif ip_assign_scheme:=none network:=true
+
+ updateColumns.put("NAT", new Atom<>(false) );
+ updateColumns.put("enabled", new Atom<>(true) );
+ updateColumns.put("if_name", new Atom<>(ifName) );
+ updateColumns.put("if_type", new Atom<>("vif") );
+ updateColumns.put("ip_assign_scheme", new Atom<>("none") );
+ updateColumns.put("network", new Atom<>(true) );
+
+ Row row = new Row(updateColumns);
+ operations.add(new Insert(wifiInetConfigDbTable, row ));
+
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ LOG.debug("Provisioned WifiInetConfig {}", ifName);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ LOG.error("Error in configureWifiInet", e);
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public void configureWifiInet(OvsdbClient ovsdbClient) {
+ Map provisionedWifiInetConfigs = getProvisionedWifiInetConfigs(ovsdbClient);
+ LOG.debug("Existing WifiInetConfigs: {}", provisionedWifiInetConfigs.keySet());
+
+ String ifName = homeAp24;
+ if(!provisionedWifiInetConfigs.containsKey(ifName)) {
+ configureWifiInet(ovsdbClient, provisionedWifiInetConfigs, ifName);
+ }
+
+ ifName = homeApL50;
+ if(!provisionedWifiInetConfigs.containsKey(ifName)) {
+ configureWifiInet(ovsdbClient, provisionedWifiInetConfigs, ifName);
+ }
+
+ }
+
+ public void configureStats(OvsdbClient ovsdbClient) {
+
+ Map provisionedWifiStatsConfigs = getProvisionedWifiStatsConfigs(ovsdbClient);
+
+ try {
+ List operations = new ArrayList<>();
+ Map updateColumns = new HashMap<>();
+ Row row;
+
+ Set channelSet = new HashSet<>();
+ channelSet.add(1);
+ channelSet.add(6);
+ channelSet.add(11);
+ com.vmware.ovsdb.protocol.operation.notation.Set channels = com.vmware.ovsdb.protocol.operation.notation.Set.of(channelSet);
+
+ Map thresholdMap = new HashMap<>();
+ thresholdMap.put("max_delay", 600);
+ thresholdMap.put("util", 10);
+
+ @SuppressWarnings("unchecked")
+ com.vmware.ovsdb.protocol.operation.notation.Map thresholds = com.vmware.ovsdb.protocol.operation.notation.Map.of(thresholdMap);
+
+ if(!provisionedWifiStatsConfigs.containsKey("2.4G_device_null")) {
+ //
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("2.4G") );
+ updateColumns.put("reporting_interval", new Atom<>(10) );
+ updateColumns.put("sampling_interval", new Atom<>(0) );
+ updateColumns.put("stats_type", new Atom<>("device") );
+ //updateColumns.put("survey_interval_ms", new Atom<>(10) );
+ //updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("5GL_survey_on-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("5GL") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("survey") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("2.4G_survey_off-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("2.4G") );
+ updateColumns.put("reporting_interval", new Atom<>(120) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("survey") );
+ updateColumns.put("survey_interval_ms", new Atom<>(50) );
+ updateColumns.put("survey_type", new Atom<>("off-chan") );
+ updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("2.4G_neighbor_off-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("2.4G") );
+ updateColumns.put("reporting_interval", new Atom<>(120) );
+ updateColumns.put("sampling_interval", new Atom<>(0) );
+ updateColumns.put("stats_type", new Atom<>("neighbor") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("off-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("5GU_neighbor_on-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("5GU") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(0) );
+ updateColumns.put("stats_type", new Atom<>("neighbor") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("5GL_client_null")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("5GL") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("client") );
+ //updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ //updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("5GU_client_null")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("5GU") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("client") );
+ //updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ //updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("2.4G_survey_on-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("2.4G") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("survey") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("2.4G_client_null")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("2.4G") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("client") );
+ //updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ //updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("2.4G_neighbor_on-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("2.4G") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(0) );
+ updateColumns.put("stats_type", new Atom<>("neighbor") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("5GU_survey_on-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("5GU") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(10) );
+ updateColumns.put("stats_type", new Atom<>("survey") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!provisionedWifiStatsConfigs.containsKey("5GL_neighbor_on-chan")) {
+ //
+ updateColumns = new HashMap<>();
+ //updateColumns.put("channel_list", channels );
+ updateColumns.put("radio_type", new Atom<>("5GL") );
+ updateColumns.put("reporting_interval", new Atom<>(60) );
+ updateColumns.put("sampling_interval", new Atom<>(0) );
+ updateColumns.put("stats_type", new Atom<>("neighbor") );
+ updateColumns.put("survey_interval_ms", new Atom<>(0) );
+ updateColumns.put("survey_type", new Atom<>("on-chan") );
+ //updateColumns.put("threshold", thresholds );
+
+
+ row = new Row(updateColumns );
+ operations.add(new Insert(wifiStatsConfigDbTable, row ));
+ //
+ }
+
+ if(!operations.isEmpty()) {
+ CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations);
+ OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS);
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("Updated {}:", wifiStatsConfigDbTable);
+
+ for(OperationResult res : result) {
+ LOG.debug("Op Result {}", res);
+ }
+ }
+ }
+
+ } catch(OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/BridgeInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/BridgeInfo.java
new file mode 100644
index 0000000..bb8d0db
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/BridgeInfo.java
@@ -0,0 +1,33 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+public class BridgeInfo implements Cloneable{
+
+ public Set portUuids;
+
+ public String name;
+ public Uuid uuid;
+
+ @Override
+ public BridgeInfo clone() {
+ try {
+ BridgeInfo ret = (BridgeInfo)super.clone();
+ if(portUuids!=null) {
+ ret.portUuids = new HashSet<>(this.portUuids);
+ }
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("BridgeInfo [portUuids=%s, name=%s, uuid=%s]", portUuids, name, uuid);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/ConnectNodeInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/ConnectNodeInfo.java
new file mode 100644
index 0000000..8c89990
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/ConnectNodeInfo.java
@@ -0,0 +1,33 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ConnectNodeInfo implements Cloneable{
+ public Map mqttSettings;
+ public String redirectorAddr;
+ public String managerAddr;
+ public String skuNumber;
+ public String serialNumber;
+
+ @Override
+ public ConnectNodeInfo clone() {
+ try {
+ ConnectNodeInfo ret = (ConnectNodeInfo)super.clone();
+ if (this.mqttSettings!=null) {
+ ret.mqttSettings = new HashMap<>(this.mqttSettings);
+ }
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "ConnectNodeInfo [mqttSettings=%s, redirectorAddr=%s, managerAddr=%s, skuNumber=%s, serialNumber=%s]",
+ mqttSettings, redirectorAddr, managerAddr, skuNumber, serialNumber);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/InterfaceInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/InterfaceInfo.java
new file mode 100644
index 0000000..11e9149
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/InterfaceInfo.java
@@ -0,0 +1,33 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+public class InterfaceInfo implements Cloneable{
+
+ public String adminState;
+ public String linkState;
+ public int ifIndex;
+ public int mtu;
+ public int ofport;
+
+ public String name;
+ public Uuid uuid;
+
+ @Override
+ public InterfaceInfo clone() {
+ try {
+ InterfaceInfo ret = (InterfaceInfo)super.clone();
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "InterfaceInfo [adminState=%s, linkState=%s, ifIndex=%s, mtu=%s, ofport=%s, name=%s, uuid=%s]",
+ adminState, linkState, ifIndex, mtu, ofport, name, uuid);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/PortInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/PortInfo.java
new file mode 100644
index 0000000..3855e11
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/PortInfo.java
@@ -0,0 +1,33 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+public class PortInfo implements Cloneable{
+
+ public Set interfaceUuids;
+
+ public String name;
+ public Uuid uuid;
+
+ @Override
+ public PortInfo clone() {
+ try {
+ PortInfo ret = (PortInfo)super.clone();
+ if(interfaceUuids!=null) {
+ ret.interfaceUuids = new HashSet<>(this.interfaceUuids);
+ }
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PortInfo [interfaceUuids=%s, name=%s, uuid=%s]", interfaceUuids, name, uuid);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiInetConfigInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiInetConfigInfo.java
new file mode 100644
index 0000000..a74c16a
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiInetConfigInfo.java
@@ -0,0 +1,33 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+public class WifiInetConfigInfo implements Cloneable{
+
+ public boolean nat;
+ public boolean enabled;
+ public String ifName;
+ public String ifType;
+ public String ipAssignScheme;
+ public boolean network;
+
+ public Uuid uuid;
+
+ @Override
+ public WifiInetConfigInfo clone() {
+ try {
+ WifiInetConfigInfo ret = (WifiInetConfigInfo)super.clone();
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "WifiInetConfigInfo [nat=%s, enabled=%s, ifName=%s, ifType=%s, ipAssignScheme=%s, network=%s, uuid=%s]",
+ nat, enabled, ifName, ifType, ipAssignScheme, network, uuid);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiRadioConfigInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiRadioConfigInfo.java
new file mode 100644
index 0000000..63c7fe4
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiRadioConfigInfo.java
@@ -0,0 +1,51 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+public class WifiRadioConfigInfo implements Cloneable{
+
+ public Set vifConfigUuids;
+
+ public String freqBand;
+ public int channel;
+ public Integer txPower;
+ public String channelMode;
+ public boolean enabled;
+ public String htMode;
+ public Map hwConfig;
+ public String country;
+
+ public String ifName;
+ public Uuid uuid;
+
+ @Override
+ public WifiRadioConfigInfo clone() {
+ try {
+ WifiRadioConfigInfo ret = (WifiRadioConfigInfo)super.clone();
+ if(vifConfigUuids!=null) {
+ ret.vifConfigUuids = new HashSet<>(this.vifConfigUuids);
+ }
+
+ if(hwConfig!=null) {
+ ret.hwConfig = new HashMap<>(this.hwConfig);
+ }
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "WifiRadioConfigInfo [vifConfigUuids=%s, freqBand=%s, channel=%s, txPower=%s, channelMode=%s, enabled=%s, htMode=%s, hwConfig=%s, country=%s, ifName=%s, uuid=%s]",
+ vifConfigUuids, freqBand, channel, txPower, channelMode, enabled, htMode, hwConfig, country, ifName,
+ uuid);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiStatsConfigInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiStatsConfigInfo.java
new file mode 100644
index 0000000..1f2cade
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiStatsConfigInfo.java
@@ -0,0 +1,53 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+/**
+ * radio_type + stats_type + survey_type identifies a record
+ *
+ */
+public class WifiStatsConfigInfo implements Cloneable{
+
+ public Set channelList;
+ public String radioType;
+ public int reportingInterval;
+ public int samplingInterval;
+ public String statsType;
+ public int surveyIntervalMs;
+ public String surveyType;
+ public Map threshold;
+
+ public Uuid uuid;
+
+ @Override
+ public WifiStatsConfigInfo clone() {
+ try {
+ WifiStatsConfigInfo ret = (WifiStatsConfigInfo)super.clone();
+ if(channelList!=null) {
+ ret.channelList = new HashSet<>(this.channelList);
+ }
+ if(threshold!=null) {
+ ret.threshold = new HashMap<>(this.threshold);
+ }
+
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "WifiStatsConfigInfo [channelList=%s, radioType=%s, reportingInterval=%s, samplingInterval=%s, statsType=%s, surveyIntervalMs=%s, surveyType=%s, threshold=%s, uuid=%s]",
+ channelList, radioType, reportingInterval, samplingInterval, statsType, surveyIntervalMs,
+ surveyType, threshold, uuid);
+ }
+
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiVifConfigInfo.java b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiVifConfigInfo.java
new file mode 100644
index 0000000..c9c2d68
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/ovsdb/dao/models/WifiVifConfigInfo.java
@@ -0,0 +1,48 @@
+package ai.connectus.opensync.ovsdb.dao.models;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.vmware.ovsdb.protocol.operation.notation.Uuid;
+
+public class WifiVifConfigInfo implements Cloneable{
+
+ public String bridge;
+ public int btm;
+ public boolean enabled;
+ public int ftPsk;
+ public int groupRekey;
+ public String ifName;
+ public String mode;
+ public int rrm;
+ public String ssid;
+ public String ssidBroadcast;
+ public boolean uapsdEnable;
+ public int vifRadioIdx;
+ public Map security;
+
+ public Uuid uuid;
+
+ @Override
+ public WifiVifConfigInfo clone() {
+ try {
+ WifiVifConfigInfo ret = (WifiVifConfigInfo)super.clone();
+
+ if(security!=null) {
+ ret.security = new HashMap<>(this.security);
+ }
+ return ret;
+ }catch(CloneNotSupportedException e) {
+ throw new IllegalStateException("Cannot clone ", e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "WifiVifConfigInfo [bridge=%s, btm=%s, enabled=%s, ftPsk=%s, groupRekey=%s, ifName=%s, mode=%s, rrm=%s, ssid=%s, ssidBroadcast=%s, uapsdEnable=%s, vifRadioIdx=%s, security=%s, uuid=%s]",
+ bridge, btm, enabled, ftPsk, groupRekey, ifName, mode, rrm, ssid, ssidBroadcast, uapsdEnable,
+ vifRadioIdx, security, uuid);
+ }
+
+}
\ No newline at end of file
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/util/SslUtil.java b/opensync_gateway/src/main/java/ai/connectus/opensync/util/SslUtil.java
new file mode 100644
index 0000000..918fa31
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/util/SslUtil.java
@@ -0,0 +1,36 @@
+package ai.connectus.opensync.util;
+
+public class SslUtil {
+
+ /**
+ * Examples:
+ *
+ * subject=CN = PP302X-EX, C = US, O = Plume Design Inc., L = Palo Alto, ST = CA, emailAddress = support@plumewifi.com
+ * subject=C = CA, ST = Ontario, L = Ottawa, O = WhizControl Canada Inc, OU = Research and Develpoment, CN = dev-ap-0001, emailAddress = devadmin@123wlan.com
+ *
+ * @param subjectDn
+ * @return Value of the CN attribute of the supplied subject DN, or empty string if it cannot be extracted
+ */
+ public static String extractCN(String subjectDn) {
+ if(subjectDn==null || subjectDn.isEmpty()) {
+ return "";
+ }
+ String[] attrs = subjectDn.split(",");
+ String tmp;
+ int idx;
+ for(String attr : attrs) {
+ tmp = attr.trim();
+ if(tmp.startsWith("CN")) {
+ idx = tmp.indexOf('=');
+ if(idx>0) {
+ return tmp.substring(idx + 1).trim();
+ } else {
+ return "";
+ }
+ }
+ }
+
+ return "";
+
+ }
+}
diff --git a/opensync_gateway/src/main/java/ai/connectus/opensync/util/ZlibUtil.java b/opensync_gateway/src/main/java/ai/connectus/opensync/util/ZlibUtil.java
new file mode 100644
index 0000000..06f1285
--- /dev/null
+++ b/opensync_gateway/src/main/java/ai/connectus/opensync/util/ZlibUtil.java
@@ -0,0 +1,105 @@
+package ai.connectus.opensync.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+public class ZlibUtil {
+
+ public static final int MAX_BUFFER_SIZE = 8192;
+
+ public static byte[] compress(byte[] bytesToCompress) {
+ if(bytesToCompress == null) {
+ return null;
+ }
+
+ if(bytesToCompress.length==0) {
+ return new byte[0];
+ }
+
+ Deflater deflater = new Deflater();
+ deflater.setInput(bytesToCompress);
+ deflater.finish();
+
+ byte[] bytesCompressed = new byte[bytesToCompress.length];
+
+ int numberOfBytesAfterCompression = deflater.deflate(bytesCompressed);
+
+ if(numberOfBytesAfterCompression == 0) {
+ throw new IllegalStateException("Compressed size is greater than original?");
+ }
+
+ byte[] returnValues = new byte[numberOfBytesAfterCompression];
+
+ System.arraycopy(bytesCompressed, 0, returnValues, 0, numberOfBytesAfterCompression);
+
+ return returnValues;
+ }
+
+ private static class SizeAndBuffer{
+ int size;
+ byte[] buffer;
+
+ public SizeAndBuffer(int size, byte[] buffer) {
+ this.size = size;
+ this.buffer = buffer;
+ }
+ }
+
+ public static byte[] decompress(byte[] bytesToDecompress)
+ {
+ if(bytesToDecompress == null) {
+ return null;
+ }
+
+ if(bytesToDecompress.length == 0) {
+ return new byte[0];
+ }
+
+ byte[] returnValues = null;
+
+ Inflater inflater = new Inflater();
+ int numberOfBytesToDecompress = bytesToDecompress.length;
+ inflater.setInput(bytesToDecompress, 0, numberOfBytesToDecompress);
+
+ int bufferSizeInBytes = numberOfBytesToDecompress;
+
+ int numberOfBytesDecompressedSoFar = 0;
+ List bytesDecompressedSoFar = new ArrayList<>();
+
+ try
+ {
+ while (!inflater.needsInput())
+ {
+ byte[] bytesDecompressedBuffer = new byte[bufferSizeInBytes];
+
+ int numberOfBytesDecompressedThisTime = inflater.inflate(bytesDecompressedBuffer);
+ numberOfBytesDecompressedSoFar += numberOfBytesDecompressedThisTime;
+
+ bytesDecompressedSoFar.add(new SizeAndBuffer(numberOfBytesDecompressedThisTime, bytesDecompressedBuffer));
+ }
+
+
+ //now stitch together all the buffers we've collected
+ returnValues = new byte[numberOfBytesDecompressedSoFar];
+ int destPos = 0;
+ int length = 0;
+
+ for(SizeAndBuffer partBuffer : bytesDecompressedSoFar) {
+ length = partBuffer.size;
+ System.arraycopy(partBuffer.buffer, 0, returnValues, destPos, length);
+ destPos += length;
+ }
+
+ } catch (DataFormatException dfe) {
+ throw new IllegalStateException(dfe);
+ }
+
+ inflater.end();
+
+ return returnValues;
+ }
+
+}
diff --git a/opensync_gateway/src/main/resources/application.properties b/opensync_gateway/src/main/resources/application.properties
new file mode 100644
index 0000000..bc43d6a
--- /dev/null
+++ b/opensync_gateway/src/main/resources/application.properties
@@ -0,0 +1,122 @@
+# see http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#common-application-properties-security for details
+
+app.name=OpenSyncManager
+
+#
+#Select spring profiles
+#
+# valid values for security profiles are: no_ssl, use_ssl
+# valid values for auth profiles are: no_auth, form_based_auth, http_basic_auth, http_digest_auth, client_certificate_auth
+#
+# this property can be overridden by application.properties in the following locations:
+# classpath root
+# current directory
+# classpath /config package
+# /config subdir of the current directory.
+# System property -Dspring.profiles.active=production
+# or specified on the command line using the switch --spring.profiles.active=dev,hsqldb
+#
+# This does not work: spring.profiles.active=${whizcontrol.core.server.security},${whizcontrol.core.server.auth},Extra_${app.name}
+# Substitution of ${} in application.properties works in general, but not for spring.profiles.active and not for spring.profiles.include properties
+#
+# *** Do not set spring.profiles.active property in this file, or be prepared for the World of Weird.
+#spring.profiles.active=a_1,a_2,integration_test
+# Example: with application.properties:spring.profiles.active=a_1,a_2,dev,integration_test and @ActiveProfiles(profiles = "test1")
+# active profiles: [profile_it_1, profile_it_2, profile_dev_1, profile_dev_2, p_1, p_2, a_1, a_2, dev, integration_test, test1]
+# What happens:
+# RealActiveProfiles.addAll(application.properties:spring.profiles.active)
+# RealActiveProfiles.addAll(application.properties:spring.profiles.include)
+# Find all other files named application-${profileName}.properties based on content of RealActiveProfiles
+# All application-${profileName}.properties:spring.profiles.include are read, and for each file:
+# RealActiveProfiles.addAll(application-${profileName}.properties:spring.profiles.include)
+# Recursively process other files named application-${profileName}.properties based on content of RealActiveProfiles
+#
+# Note that application-${profileName}.properties:spring.profiles.active values are NOT added to the RealActiveProfiles in this case.
+#
+# Another Example: with application.properties:spring.profiles.active NOT SET and @ActiveProfiles(profiles = "integration_test")
+# active profiles: [profile_it_1, profile_it_2, active_it_1, active_it_2, p_1, p_2, integration_test]
+# What happens:
+# application.properties:spring.profiles.active is read and not found
+# RealActiveProfiles.addAll(application.properties:spring.profiles.include)
+# Find all other files named application-${profileName}.properties based on content of RealActiveProfiles
+# Found application-integration_test.properties file
+# RealActiveProfiles.addAll(application-integration_test.properties:spring.profiles.active)
+# RealActiveProfiles.addAll(application-integration_test.properties:spring.profiles.include)
+# Find all other files named application-${profileName}.properties based on content of RealActiveProfiles
+# All application-${profileName}.properties:spring.profiles.include are read, and for each file:
+# RealActiveProfiles.addAll(application-${profileName}.properties:spring.profiles.include)
+# Recursively process other files named application-${profileName}.properties based on content of RealActiveProfiles
+#
+# Note that only application-integration_test.properties:spring.profiles.active is read,
+# all other application-${profileName}.properties:spring.profiles.active values
+# are NOT added to the RealActiveProfiles in this case.
+#
+# Summary:
+# 1. Only the first available property application*.properties:spring.profiles.active is read and added to RealActiveProfiles
+# 2. All properties application*.properties:spring.profiles.include are read, and their values are added to RealActiveProfiles
+# 3. Many application*.properties can be read during initialization (i.e. one can include a profile name that is referring to another)
+#
+# ***
+#
+# Use spring.profiles.active property for unit/integration tests to select proper application-*.properties file
+# - this can be done by placing annotation @ActiveProfiles(profiles = "integration_test") on the test classes
+#
+# Use spring.profiles.active property for specific deployments - staging/cloud to select proper application-*.properties file
+# - this can be done by using SystemProperty -Dspring.profiles.active=cloud
+#
+# Deployment-specific properties can be configured in other property files, like persistence-${envTarget:dev}.properties
+# where value for property envTarget can be set using any mechanism, including placing it in the application-*.properties
+#
+#
+# Use spring.profiles.include property to specify static collection of profiles that are
+# always present in this configuration, regardless of spring.profiles.active property
+# Note: this property is additive, its value is always added to the list of active profiles
+#spring.profiles.include=use_ssl,http_digest_auth,customer-credential-datastore-inmemory
+#spring.profiles.include=no_ssl,no_auth
+#spring.profiles.include=use_ssl,client_certificate_auth
+spring.profiles.include=use_ssl_with_client_cert_and_basic_auth,client_certificate_and_basic_auth,rest-template-single-user-per-service-digest-auth,use_single_ds
+
+whizcontrol.equipmentAndNetworkManagementServiceBaseUrl=https://localhost:9094
+
+#used by *-remote client classes when they authenticate their requests
+whizcontrol.httpClientConfig=classpath:httpClientConfig.json
+
+#this user/password is used together with http_digest_auth and http_basic_auth spring profiles
+whizcontrol.serviceUser=user
+whizcontrol.servicePassword=password
+
+spring.main.show-banner=false
+server.port=9096
+
+#this port is used by secondary server connector, it is protected by digest authentication, while primary server.port is protected by client certificate auth
+whizcontrol.secondaryPort=7071
+
+#this server only supports REST requests, CSRF would get in the way
+whizcontrol.csrf-enabled=false
+whizcontrol.emailVerificationTokenExpiryMs=600
+whizcontrol.passwordResetTokenExpiryMs=3600
+
+whizcontrol.customerAccountManagementServiceBaseUrl=https://localhost:9092
+whizcontrol.orderAndSubscriptionManagementServiceBaseUrl=https://localhost:9093
+whizcontrol.equipmentAndNetworkManagementServiceBaseUrl=https://localhost:9094
+whizcontrol.equipmentConfigurationManagerServiceBaseUrl=https://localhost:9082
+whizcontrol.equipmentStatusAndAlarmCollectorServiceBaseUrl=https://localhost:9083
+whizcontrol.equipmentMetricsCollectorServiceBaseUrl=https://localhost:9085
+whizcontrol.equipmentRoutingServiceBaseUrl=https://localhost:9081
+whizcontrol.firmwareManagementServiceBaseUrl=https://localhost:9072
+whizcontrol.equipmentEventCollectorServiceBaseUrl=https://localhost:9076
+
+#server.session-timeout= # session timeout in seconds
+#server.tomcat.max-threads = 0 # number of threads in protocol handler
+
+#server.context-path= # the context path, defaults to '/'
+#server.servlet-path= # the servlet path, defaults to '/'
+#server.tomcat.access-log-pattern= # log pattern of the access log
+#server.tomcat.access-log-enabled=false # is access logging enabled
+
+# pretty print JSON
+spring.jackson.serialization.INDENT_OUTPUT=TRUE
+# sort keys
+#http.mappers.json-sort-keys=false
+
+#spring.jmx.enabled=true # Expose MBeans from Spring
diff --git a/opensync_gateway/src/main/resources/logback.xml b/opensync_gateway/src/main/resources/logback.xml
new file mode 100644
index 0000000..e9e2846
--- /dev/null
+++ b/opensync_gateway/src/main/resources/logback.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ %d{yyyy-MM-DD HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+ /var/log/a2w/opensyncgw.log
+ true
+
+ %date %level [%thread] %logger{36} [%file:%line] %msg%n
+
+
+ /var/log/a2w/opensyncgw.%i.log.gz
+ 1
+ 3
+
+
+ 20MB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/opensync_gateway/src/main/resources/run.sh b/opensync_gateway/src/main/resources/run.sh
new file mode 100644
index 0000000..70fbb77
--- /dev/null
+++ b/opensync_gateway/src/main/resources/run.sh
@@ -0,0 +1,30 @@
+SSL_PROPS=" "
+SSL_PROPS+=" -Dssl.props=file:///home/ec2-user/opensync/ssl.properties"
+SSL_PROPS+=" -Dwhizcontrol.httpClientConfig=file:///home/ec2-user/opensync/httpClientConfig.json"
+
+CLIENT_MQTT_SSL_PROPS=" "
+CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.keyStore=/home/ec2-user/opensync/client2Keystore.jks"
+CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.keyStorePassword=mypassword"
+CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.trustStore=/home/ec2-user/opensync/truststore.jks"
+CLIENT_MQTT_SSL_PROPS+=" -Djavax.net.ssl.trustStorePassword=mypassword"
+
+OVSDB_PROPS=" "
+OVSDB_PROPS+=" -Dconnectus.ovsdb.managerAddr=3.88.149.10"
+OVSDB_PROPS+=" -Dconnectus.ovsdb.listenPort=6640 "
+OVSDB_PROPS+=" -Dconnectus.ovsdb.redirector.listenPort=6643"
+OVSDB_PROPS+=" -Dconnectus.ovsdb.timeoutSec=30"
+OVSDB_PROPS+=" -Dconnectus.ovsdb.trustStore=/home/ec2-user/opensync/truststore.jks"
+OVSDB_PROPS+=" -Dconnectus.ovsdb.keyStore=/home/ec2-user/opensync/server.p12"
+
+MQTT_PROPS=" "
+MQTT_PROPS+=" -Dconnectus.mqttBroker.address=testportal.123wlan.com"
+MQTT_PROPS+=" -Dconnectus.mqttBroker.listenPort=1883"
+
+LOGGING_PROPS=" -Dlogging.config=file:///home/ec2-user/opensync/logback.xml"
+
+RESTAPI_PROPS=" "
+RESTAPI_PROPS+=" -Dserver.port=443"
+
+export ALL_PROPS="$SSL_PROPS $CLIENT_MQTT_SSL_PROPS $OVSDB_PROPS $MQTT_PROPS $LOGGING_PROPS $RESTAPI_PROPS"
+
+sudo java $ALL_PROPS -jar opensync_experiment-0.0.1-SNAPSHOT.jar > stdout.out 2>&1 &