14 Commits

Author SHA1 Message Date
Jun Woo Shin
0279437f5c scale testing code 2022-10-20 18:24:41 -04:00
Jun Woo Shin
c635af6c1d use eclipse temurin distribution of openjdk (#107)
Signed-off-by: Jun Woo Shin <jwoos@fb.com>
2022-10-20 09:34:09 -04:00
Jun Woo Shin
37a904087d [WIFI-11247] change host to 0.0.0.0 (#106) 2022-10-19 09:47:59 -04:00
RockyMandayam2
6df81b7fef Use device capabilities to identify radio band (#104) 2022-10-13 19:05:05 -07:00
RockyMandayam2
8171cc74ae Remove lower and upper channel limit maps (#102) 2022-10-13 09:51:18 -07:00
Jeffrey Han
215d73fee5 Fix vendorReferenceUrl in RRMConfig broken in #99 (#103) 2022-10-12 18:23:37 -07:00
RockyMandayam2
ecbf8fa644 Fix javadoc and add override decorator (#101) 2022-10-12 15:39:11 -07:00
RockyMandayam2
19928e0286 Move AVAILABLE_CHANNELS_BAND to UCentralUtils before adding 6G support (#100) 2022-10-12 15:27:11 -07:00
Jun Woo Shin
da978611d0 [WIFI-10736] Spin up separate ports for internal and external (#64)
Signed-off-by: Jun Woo Shin <jwoos@fb.com>
2022-10-12 15:45:44 -04:00
Jeffrey Han
e42eaa747b [WIFI-11196] Restructure repository into multimodule project (#99) 2022-10-12 11:57:32 -07:00
Dmitry Dunaev
264f114be2 [WIFI-10910] Chg: internal endpoint port (#98)
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>

Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-11 19:44:46 +03:00
zhiqiand
dd2b485b00 Follow-up on stats aggregation (#96)
* fix some comments from Jerrey

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix some comments

Signed-off-by: zhiqiand <zhiqian@fb.com>

Signed-off-by: zhiqiand <zhiqian@fb.com>
2022-10-10 15:59:04 -07:00
Jun Woo Shin
033d93beff Fix IE parsing (#97)
Signed-off-by: Jun Woo Shin <jwoos@fb.com>
2022-10-07 14:59:50 -04:00
zhiqiand
e5d5f7d5c0 States aggregation (#82)
* initial

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix some comments

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix comments on AggregatedState and ModelerUtils

Signed-off-by: zhiqiand <zhiqian@fb.com>

* reformat and thread-safe

Signed-off-by: zhiqiand <zhiqian@fb.com>

* add buffer size for state

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix some comments

Signed-off-by: zhiqiand <zhiqian@fb.com>

* add javadoc

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix comments in TestUtils

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix some comments

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix some comments

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix some comments

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix tx_power

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix channel number

Signed-off-by: zhiqiand <zhiqian@fb.com>

* fix long type

Signed-off-by: zhiqiand <zhiqian@fb.com>

Signed-off-by: zhiqiand <zhiqian@fb.com>
2022-10-06 10:10:20 -07:00
139 changed files with 3447 additions and 1245 deletions

View File

@@ -18,7 +18,7 @@ jobs:
distribution: 'adopt'
cache: maven
- name: Build with Maven
run: mvn javadoc:javadoc
run: mvn javadoc:aggregate
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:

11
.gitignore vendored
View File

@@ -1,12 +1,9 @@
/target
/*.log*
/device_config.json
/settings.json
/topology.json
/target/
*/target/
# Eclipse
/.settings/
/bin/
.settings/
bin/
.metadata
.classpath
.project

View File

@@ -1,7 +1,7 @@
FROM maven:3-jdk-11 as build
FROM maven:3-eclipse-temurin-11 as build
WORKDIR /usr/src/java
COPY . .
RUN mvn clean package -DappendVersionString="$(./scripts/get_build_version.sh)"
RUN mvn clean package -pl owrrm -am -DappendVersionString="$(./scripts/get_build_version.sh)"
FROM adoptopenjdk/openjdk11-openj9:latest
RUN apt-get update && apt-get install -y gettext-base wget
@@ -10,8 +10,8 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr
RUN mkdir /owrrm-data
WORKDIR /usr/src/java
COPY docker-entrypoint.sh /
COPY --from=build /usr/src/java/target/openwifi-rrm.jar /usr/local/bin/
EXPOSE 16789
COPY --from=build /usr/src/java/owrrm/target/openwifi-rrm.jar /usr/local/bin/
EXPOSE 16789 16790
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["java", "-XX:+IdleTuningGcOnIdle", "-Xtune:virtualized", \
"-jar", "/usr/local/bin/openwifi-rrm.jar", \

View File

@@ -1,12 +1,10 @@
# OpenWiFi RRM Service
OpenWiFi uCentral-based radio resource management (RRM) service, providing a
cloud-based Wi-Fi RRM layer for APs running the OpenWiFi SDK.
[See here](owrrm/README.md) for details.
This service collects data from OpenWiFi APs (e.g. Wi-Fi scans, stats,
capabilities) via the uCentral Gateway and Kafka, and integrates with the
OpenWiFi Provisioning service to perform optimization across configured
"venues". It pushes new device configuration parameters to APs after RRM
algorithms are run (manually or periodically).
## Project Structure
This is an [Apache Maven] project with the following modules:
* `lib-cloudsdk` - OpenWiFi CloudSDK Java Library
* `owrrm` - OpenWiFi RRM Service
## Requirements
* **Running:** JRE 11.
@@ -16,7 +14,7 @@ algorithms are run (manually or periodically).
```
$ mvn package [-DskipTests]
```
This will build a runnable JAR located at `target/openwifi-rrm.jar`.
This will build a runnable JAR located at `owrrm/target/openwifi-rrm.jar`.
Alternatively, Docker builds can be launched using the provided
[Dockerfile](Dockerfile).
@@ -27,34 +25,7 @@ $ mvn test
```
Unit tests are written using [JUnit 5].
## Usage
```
$ java -jar openwifi-rrm.jar [-h]
```
To start the service, use the `run` command while providing configuration via
either environment variables (`--config-env`) or a static JSON file
(`--config-file`, default `settings.json`). The following data is *required*:
* Service configuration
* Env: `SERVICECONFIG_PRIVATEENDPOINT`, `SERVICECONFIG_PUBLICENDPOINT`
* JSON: `serviceConfig` structure
* Kafka broker URL
* Env: `KAFKACONFIG_BOOTSTRAPSERVER`
* JSON: `kafkaConfig` structure
* MySQL database credentials
* Env: `DATABASECONFIG_SERVER`, `DATABASECONFIG_USER`, `DATABASECONFIG_PASSWORD`
* JSON: `databaseConfig` structure
## OpenAPI
This service provides an OpenAPI HTTP interface on the port specified in the
service configuration (`moduleConfig.apiServerParams`). An auto-generated
OpenAPI 3.0 document is hosted at the endpoints `/openapi.{yaml,json}` and is
written to [openapi.yaml](openapi.yaml) during the Maven "compile" phase.
## For Developers
See [IMPLEMENTATION.md](IMPLEMENTATION.md) for service architecture details and
[ALGORITHMS.md](ALGORITHMS.md) for descriptions of the RRM algorithms.
## Code Style
Code is auto-formatted using [Spotless] with a custom Eclipse style config (see
[spotless/eclipse-java-formatter.xml](spotless/eclipse-java-formatter.xml)).
This can be applied via Maven (but is *not* enforced at build time):

View File

@@ -29,8 +29,8 @@ services:
targetPort: 16789
protocol: TCP
restapiinternal:
servicePort: 17007
targetPort: 17007
servicePort: 16790
targetPort: 16790
protocol: TCP
checks:

3
lib-cloudsdk/README.md Normal file
View File

@@ -0,0 +1,3 @@
# OpenWiFi CloudSDK Java Library
A Java library providing clients and models for the OpenWiFi uCentral-based
CloudSDK.

80
lib-cloudsdk/pom.xml Normal file
View File

@@ -0,0 +1,80 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>openwifi-cloudsdk</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>com.facebook</groupId>
<artifactId>openwifi-base</artifactId>
<version>2.7.0</version>
</parent>
<properties>
<!-- Hack for static files located in root project -->
<myproject.root>${project.basedir}/..</myproject.root>
</properties>
<build>
<finalName>openwifi-cloudsdk</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifi.cloudsdk;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.facebook.openwifi.cloudsdk.models.ap.State.Interface.SSID.Association;
import com.facebook.openwifi.cloudsdk.models.ap.State.Interface.SSID.Association.Rate;
/**
* Aggregation model for State aggregation. Only contains info useful for
* analysis.
*/
public class AggregatedState {
/** Rate information with aggregated fields. */
public static class AggregatedRate {
/**
* This is the common bitRate for all the aggregated fields.
*/
public long bitRate;
/**
* This is the common channel width for all the aggregated fields.
*/
public int chWidth;
/**
* Aggregated fields mcs
*/
public List<Integer> mcs = new ArrayList<>();
/** Constructor with no args */
private AggregatedRate() {}
/** Add a Rate to the AggregatedRate */
private void add(Rate rate) {
if (rate == null) {
return;
}
if (mcs.isEmpty()) {
bitRate = rate.bitrate;
chWidth = rate.chwidth;
}
mcs.add(rate.mcs);
}
/**
* Add an AggregatedRate with the same channel_width to the
* AggregatedRate
*/
private void add(AggregatedRate rate) {
if (rate == null || rate.chWidth != chWidth) {
return;
}
if (mcs.isEmpty()) {
bitRate = rate.bitRate;
chWidth = rate.chWidth;
}
mcs.addAll(rate.mcs);
}
}
/**
* Radio information with channel, channel_width and tx_power.
*/
public static class Radio {
public int channel;
public int channelWidth;
public int txPower;
private Radio() {}
public Radio(int channel, int channelWidth, int txPower) {
this.channel = channel;
this.channelWidth = channelWidth;
this.txPower = txPower;
}
private Radio(Map<String, Integer> radioInfo) {
channel = radioInfo.getOrDefault("channel", -1);
channelWidth = radioInfo.getOrDefault("channel_width", -1);
txPower = radioInfo.getOrDefault("tx_power", -1);
}
@Override
public int hashCode() {
return Objects.hash(channel, channelWidth, txPower);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Radio other = (Radio) obj;
return channel == other.channel &&
channelWidth == other.channelWidth && txPower == other.txPower;
}
}
public String bssid;
public String station;
public long connected;
public long inactive;
public List<Integer> rssi;
public long rxBytes;
public long rxPackets;
public AggregatedRate rxRate;
public long txBytes;
public long txDuration;
public long txFailed;
public long txPackets;
public AggregatedRate txRate;
public long txRetries;
public int ackSignal;
public int ackSignalAvg;
public Radio radio;
/** Constructor with no args */
public AggregatedState() {
this.rxRate = new AggregatedRate();
this.txRate = new AggregatedRate();
this.rssi = new ArrayList<>();
this.radio = new Radio();
}
/** Construct from Association and radio */
public AggregatedState(
Association association,
Map<String, Integer> radioInfo
) {
this.rxRate = new AggregatedRate();
this.txRate = new AggregatedRate();
this.rssi = new ArrayList<>();
this.bssid = association.bssid;
this.station = association.station;
this.connected = association.connected;
this.inactive = association.inactive;
this.rssi.add(association.rssi);
this.rxBytes = association.rx_bytes;
this.rxPackets = association.rx_packets;
this.rxRate.add(association.rx_rate);
this.txBytes = association.tx_bytes;
this.txDuration = association.tx_duration;
this.txFailed = association.tx_failed;
this.txPackets = association.tx_packets;
this.txRate.add(association.tx_rate);
this.txRetries = association.tx_retries;
this.ackSignal = association.ack_signal;
this.ackSignalAvg = association.ack_signal_avg;
this.radio = new Radio(radioInfo);
}
/**
* Check whether the passed-in AggregatedState and this one match for aggregation.
* If the two match in bssid, station and radio. Then they could be aggregated.
*
* @param state the reference AggregatedState with which to check with.
* @return boolean return true if the two matches for aggregation.
*/
public boolean matchesForAggregation(AggregatedState state) {
return bssid == state.bssid && station == state.station &&
Objects.equals(radio, state.radio);
}
/**
* Add an AggregatedState to this AggregatedState. Succeed only when the two
* match for aggregation.
*
* @param state input AggregatedState
* @return boolean true if the two match in bssid, station, channel,
* channel_width and tx_power
*/
public boolean add(AggregatedState state) {
if (matchesForAggregation(state)) {
this.rssi.addAll(state.rssi);
this.rxRate.add(state.rxRate);
this.txRate.add(state.txRate);
return true;
}
return false;
}
}

View File

@@ -6,14 +6,14 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import java.util.Objects;
import com.facebook.openwifirrm.ucentral.informationelement.Country;
import com.facebook.openwifirrm.ucentral.informationelement.LocalPowerConstraint;
import com.facebook.openwifirrm.ucentral.informationelement.QbssLoad;
import com.facebook.openwifirrm.ucentral.informationelement.TxPwrInfo;
import com.facebook.openwifi.cloudsdk.ies.Country;
import com.facebook.openwifi.cloudsdk.ies.LocalPowerConstraint;
import com.facebook.openwifi.cloudsdk.ies.QbssLoad;
import com.facebook.openwifi.cloudsdk.ies.TxPwrInfo;
/** Wrapper class containing information elements */
public final class InformationElements {

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import java.util.HashSet;
import java.util.Set;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import java.util.Collections;
import java.util.HashMap;
@@ -20,22 +20,21 @@ import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.RRMConfig.UCentralConfig.UCentralSocketParams;
import com.facebook.openwifirrm.ucentral.gw.models.CommandInfo;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceCapabilities;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceConfigureRequest;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceListWithStatus;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceWithStatus;
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
import com.facebook.openwifirrm.ucentral.gw.models.StatisticsRecords;
import com.facebook.openwifirrm.ucentral.gw.models.SystemInfoResults;
import com.facebook.openwifirrm.ucentral.gw.models.TokenValidationResult;
import com.facebook.openwifirrm.ucentral.gw.models.WifiScanRequest;
import com.facebook.openwifirrm.ucentral.prov.models.EntityList;
import com.facebook.openwifirrm.ucentral.prov.models.InventoryTagList;
import com.facebook.openwifirrm.ucentral.prov.models.RRMDetails;
import com.facebook.openwifirrm.ucentral.prov.models.SerialNumberList;
import com.facebook.openwifirrm.ucentral.prov.models.VenueList;
import com.facebook.openwifi.cloudsdk.models.gw.CommandInfo;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceCapabilities;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceConfigureRequest;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceListWithStatus;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceWithStatus;
import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
import com.facebook.openwifi.cloudsdk.models.gw.StatisticsRecords;
import com.facebook.openwifi.cloudsdk.models.gw.SystemInfoResults;
import com.facebook.openwifi.cloudsdk.models.gw.TokenValidationResult;
import com.facebook.openwifi.cloudsdk.models.gw.WifiScanRequest;
import com.facebook.openwifi.cloudsdk.models.prov.EntityList;
import com.facebook.openwifi.cloudsdk.models.prov.InventoryTagList;
import com.facebook.openwifi.cloudsdk.models.prov.RRMDetails;
import com.facebook.openwifi.cloudsdk.models.prov.SerialNumberList;
import com.facebook.openwifi.cloudsdk.models.prov.VenueList;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
@@ -127,8 +126,14 @@ public class UCentralClient {
/** uCentral password */
private final String password;
/** Socket parameters */
private final UCentralSocketParams socketParams;
/** Connection timeout for all requests, in ms */
private final int connectTimeoutMs;
/** Socket timeout for all requests, in ms */
private final int socketTimeoutMs;
/** Socket timeout for wifi scan requests, in ms */
private final int wifiScanTimeoutMs;
/** The learned service endpoints. */
private final Map<String, ServiceEvent> serviceEndpoints = new HashMap<>();
@@ -147,7 +152,9 @@ public class UCentralClient {
* (if needed)
* @param username uCentral username (for public endpoints only)
* @param password uCentral password (for public endpoints only)
* @param socketParams Socket parameters
* @param connectTimeoutMs connection timeout for all requests, in ms
* @param socketTimeoutMs socket timeout for all requests, in ms
* @param wifiScanTimeoutMs socket timeout for wifi scan requests, in ms
*/
public UCentralClient(
String rrmEndpoint,
@@ -155,13 +162,17 @@ public class UCentralClient {
String uCentralSecPublicEndpoint,
String username,
String password,
UCentralSocketParams socketParams
int connectTimeoutMs,
int socketTimeoutMs,
int wifiScanTimeoutMs
) {
this.rrmEndpoint = rrmEndpoint;
this.usePublicEndpoints = usePublicEndpoints;
this.username = username;
this.password = password;
this.socketParams = socketParams;
this.connectTimeoutMs = connectTimeoutMs;
this.socketTimeoutMs = socketTimeoutMs;
this.wifiScanTimeoutMs = wifiScanTimeoutMs;
if (usePublicEndpoints) {
setServicePublicEndpoint(OWSEC_SERVICE, uCentralSecPublicEndpoint);
@@ -305,8 +316,8 @@ public class UCentralClient {
endpoint,
service,
parameters,
socketParams.connectTimeoutMs,
socketParams.socketTimeoutMs
connectTimeoutMs,
socketTimeoutMs
);
}
@@ -349,8 +360,8 @@ public class UCentralClient {
endpoint,
service,
body,
socketParams.connectTimeoutMs,
socketParams.socketTimeoutMs
connectTimeoutMs,
socketTimeoutMs
);
}
@@ -454,8 +465,8 @@ public class UCentralClient {
String.format("device/%s/wifiscan", serialNumber),
OWGW_SERVICE,
req,
socketParams.connectTimeoutMs,
socketParams.wifiScanTimeoutMs
connectTimeoutMs,
wifiScanTimeoutMs
);
if (!response.isSuccess()) {
logger.error("Error: {}", response.getBody());

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import java.util.Arrays;
import java.util.Collections;
@@ -22,7 +22,7 @@ public final class UCentralConstants {
public static final String BAND_2G = "2G";
/** String of the 5 GHz band */
public static final String BAND_5G = "5G";
/** List of all bands */
/** List of all bands ordered from lowest to highest */
public static final List<String> BANDS = Collections
.unmodifiableList(Arrays.asList(BAND_2G, BAND_5G));

View File

@@ -6,11 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -21,14 +21,11 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.RRMConfig;
import com.facebook.openwifirrm.Utils;
import com.facebook.openwifirrm.optimizers.channel.ChannelOptimizer;
import com.facebook.openwifirrm.ucentral.informationelement.Country;
import com.facebook.openwifirrm.ucentral.informationelement.LocalPowerConstraint;
import com.facebook.openwifirrm.ucentral.informationelement.QbssLoad;
import com.facebook.openwifirrm.ucentral.informationelement.TxPwrInfo;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifi.cloudsdk.ies.Country;
import com.facebook.openwifi.cloudsdk.ies.LocalPowerConstraint;
import com.facebook.openwifi.cloudsdk.ies.QbssLoad;
import com.facebook.openwifi.cloudsdk.ies.TxPwrInfo;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -47,25 +44,47 @@ public class UCentralUtils {
/** The Gson instance. */
private static final Gson gson = new Gson();
/** Map of band to the band-specific lowest available channel*/
public static final Map<String, Integer> LOWER_CHANNEL_LIMIT =
new HashMap<>();
static {
UCentralUtils.LOWER_CHANNEL_LIMIT.put(UCentralConstants.BAND_2G, 1);
UCentralUtils.LOWER_CHANNEL_LIMIT.put(UCentralConstants.BAND_5G, 36);
}
/** Map of band to the band-specific highest available channel*/
public static final Map<String, Integer> UPPER_CHANNEL_LIMIT =
new HashMap<>();
static {
UCentralUtils.UPPER_CHANNEL_LIMIT.put(UCentralConstants.BAND_2G, 11);
UCentralUtils.UPPER_CHANNEL_LIMIT.put(UCentralConstants.BAND_5G, 165);
}
/** Map from band to ordered (increasing) list of available channels */
public static final Map<String, List<Integer>> AVAILABLE_CHANNELS_BAND =
Collections
.unmodifiableMap(buildBandToChannelsMap());
// This class should not be instantiated.
private UCentralUtils() {}
/**
* Builds map from band to ordered (increasing) list of available channels.
*/
private static Map<String, List<Integer>> buildBandToChannelsMap() {
Map<String, List<Integer>> bandToChannelsMap = new HashMap<>();
bandToChannelsMap.put(
UCentralConstants.BAND_5G,
Collections.unmodifiableList(
Arrays.asList(36, 40, 44, 48, 149, 153, 157, 161, 165)
)
);
// NOTE: later, we may want to support channels 12, 13, and/or 14, if
// the AP supports it and OWF vendors will use them
bandToChannelsMap.put(
UCentralConstants.BAND_2G,
Collections.unmodifiableList(
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
)
);
return bandToChannelsMap;
}
/** Return the lowest available channel for the given band */
public static int getLowerChannelLimit(String band) {
return AVAILABLE_CHANNELS_BAND.get(band).get(0);
}
/** Return the lowest available channel for the given band */
public static int getUpperChannelLimit(String band) {
List<Integer> channels = AVAILABLE_CHANNELS_BAND.get(band);
return channels.get(channels.size() - 1);
}
/**
* Parse a JSON wifi scan result into a list of WifiScanEntry objects.
*
@@ -149,7 +168,7 @@ public class UCentralUtils {
break;
}
} catch (Exception e) {
logger.debug("Skipping invalid IE {}", ie);
logger.error(String.format("Skipping invalid IE %s", ie), e);
continue;
}
}
@@ -399,47 +418,6 @@ public class UCentralUtils {
return bssidMap;
}
/** Generate the RRM service key. */
public static String generateServiceKey(
RRMConfig.ServiceConfig serviceConfig
) {
try {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
sha256.update(serviceConfig.publicEndpoint.getBytes());
sha256.update(serviceConfig.privateEndpoint.getBytes());
return Utils.bytesToHex(sha256.digest());
} catch (NoSuchAlgorithmException e) {
logger.error("Unable to generate service key", e);
return "";
}
}
/**
* Converts channel number to that channel's center frequency in MHz.
*
* @param channel channel number. See
* {@link ChannelOptimizer#AVAILABLE_CHANNELS_BAND} for channels
* in each band.
* @return the center frequency of the given channel in MHz
*/
public static int channelToFrequencyMHz(int channel) {
if (
ChannelOptimizer.AVAILABLE_CHANNELS_BAND
.get(UCentralConstants.BAND_2G)
.contains(channel)
) {
return 2407 + 5 * channel;
} else if (
ChannelOptimizer.AVAILABLE_CHANNELS_BAND
.get(UCentralConstants.BAND_5G)
.contains(channel)
) {
return 5000 + channel;
} else {
throw new IllegalArgumentException("Must provide a valid channel.");
}
}
/**
* Determines if the given channel is in the given band.
*
@@ -448,24 +426,16 @@ public class UCentralUtils {
* @return true if the given channel is in the given band; false otherwise
*/
public static boolean isChannelInBand(int channel, String band) {
return LOWER_CHANNEL_LIMIT.get(band) <= channel &&
channel <= UPPER_CHANNEL_LIMIT.get(band);
return AVAILABLE_CHANNELS_BAND.get(band).contains(channel);
}
/**
* Given the channel, gets the band by checking lower bound and upper bound
* of each band
*
* @param channel channel number
* @return band if the channel can be mapped to a valid band; null otherwise
*/
public static String getBandFromChannel(int channel) {
for (String band : UCentralConstants.BANDS) {
if (isChannelInBand(channel, band)) {
return band;
}
/** Return which band contains the given frequency (MHz). */
public static String freqToBand(int freqMHz) {
if (2412 <= freqMHz && freqMHz <= 2484) {
return "2G";
} else {
return "5G";
}
return null;
}
/**

View File

@@ -6,11 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import java.util.Objects;
import com.facebook.openwifirrm.ucentral.models.WifiScanEntryResult;
import com.facebook.openwifi.cloudsdk.models.ap.WifiScanEntryResult;
/**
* Extends {@link WifiScanEntryResult} to track the response time of the entry.

View File

@@ -6,16 +6,13 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -25,8 +22,6 @@ import com.google.gson.JsonObject;
* javadocs is taken from the specification.
*/
public class Country {
private static final Logger logger = LoggerFactory.getLogger(Country.class);
/** Defined in 802.11 */
public static final int TYPE = 7;
@@ -125,8 +120,9 @@ public class Country {
JsonElement constraintsObject = contents.get("constraints");
if (constraintsObject != null) {
for (JsonElement jsonElement : constraintsObject.getAsJsonArray()) {
JsonObject innerElem = jsonElement.getAsJsonObject();
CountryInfo countryInfo =
CountryInfo.parse(jsonElement.getAsJsonObject());
CountryInfo.parse(innerElem.get("Country Info").getAsJsonObject());
constraints.add(countryInfo);
}
}

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import java.util.Arrays;
import java.util.Objects;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import java.util.Objects;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import java.util.Objects;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import java.util.Objects;
@@ -25,7 +25,7 @@ public class TxPwrInfo {
public static final int TYPE = 195;
/** Local maximum transmit power for 20 MHz. Required field. */
public final Integer localMaxTxPwrConstraint20MHz;
public final int localMaxTxPwrConstraint20MHz;
/** Local maximum transmit power for 40 MHz. Optional field. */
public final Integer localMaxTxPwrConstraint40MHz;
/** Local maximum transmit power for 80 MHz. Optional field. */
@@ -36,9 +36,9 @@ public class TxPwrInfo {
/** Constructor */
public TxPwrInfo(
int localMaxTxPwrConstraint20MHz,
int localMaxTxPwrConstraint40MHz,
int localMaxTxPwrConstraint80MHz,
int localMaxTxPwrConstraint160MHz
Integer localMaxTxPwrConstraint40MHz,
Integer localMaxTxPwrConstraint80MHz,
Integer localMaxTxPwrConstraint160MHz
) {
this.localMaxTxPwrConstraint20MHz = localMaxTxPwrConstraint20MHz;
this.localMaxTxPwrConstraint40MHz = localMaxTxPwrConstraint40MHz;
@@ -48,16 +48,17 @@ public class TxPwrInfo {
/** Parse TxPwrInfo IE from appropriate Json object. */
public static TxPwrInfo parse(JsonObject contents) {
JsonObject innerObj = contents.get("Tx Pwr Info").getAsJsonObject();
// required field
int localMaxTxPwrConstraint20MHz =
contents.get("Local Max Tx Pwr Constraint 20MHz").getAsInt();
innerObj.get("Local Max Tx Pwr Constraint 20MHz").getAsInt();
// optional field
Integer localMaxTxPwrConstraint40MHz =
parseOptionalField(contents, "Local Max Tx Pwr Constraint 40MHz");
parseOptionalField(innerObj, "Local Max Tx Pwr Constraint 40MHz");
Integer localMaxTxPwrConstraint80MHz =
parseOptionalField(contents, "Local Max Tx Pwr Constraint 40MHz");
parseOptionalField(innerObj, "Local Max Tx Pwr Constraint 80MHz");
Integer localMaxTxPwrConstraint160MHz =
parseOptionalField(contents, "Local Max Tx Pwr Constraint 40MHz");
parseOptionalField(innerObj, "Local Max Tx Pwr Constraint 160MHz");
return new TxPwrInfo(
localMaxTxPwrConstraint20MHz,
localMaxTxPwrConstraint40MHz,

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import java.util.Arrays;
import java.util.Objects;

View File

@@ -6,13 +6,13 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk.kafka;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.kafka.common.errors.WakeupException;
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
/**
* Kafka runner.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk.kafka;
import java.time.Duration;
import java.util.ArrayList;
@@ -29,7 +29,8 @@ import org.apache.kafka.common.serialization.StringDeserializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
import com.google.gson.Gson;
import com.google.gson.JsonObject;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk.kafka;
import java.util.Properties;
@@ -18,7 +18,7 @@ import org.apache.kafka.common.serialization.StringSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
import com.google.gson.Gson;
/**

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.models;
package com.facebook.openwifi.cloudsdk.models.ap;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.models;
package com.facebook.openwifi.cloudsdk.models.ap;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.models;
package com.facebook.openwifi.cloudsdk.models.ap;
import java.util.Objects;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class AclTemplate {
public boolean Read;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import com.google.gson.JsonObject;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import com.google.gson.JsonObject;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class DeviceConfigureRequest {
public String serialNumber;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,6 +6,6 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public enum DeviceType { AP, SWITCH, IOT, MESH }

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class MfaAuthInfo {
public boolean enabled;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class MobilePhoneNumber {
public String number;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class NoteInfo {
public long created;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class ServiceEvent {
public static final String EVENT_JOIN = "join";

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import com.google.gson.JsonObject;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class TokenValidationResult {
public UserInfo userInfo;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public enum VerifiedCertificate {
NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class WebTokenAclTemplate {
public AclTemplate aclTemplate;

View File

@@ -6,13 +6,13 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
public class WebTokenResult {
public String access_token;
public String refresh_token;
public String token_type;
public int expires_in;
public long expires_in;
public int idle_timeout;
public String username;
public long created;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.gw.models;
package com.facebook.openwifi.cloudsdk.models.gw;
import java.util.List;

View File

@@ -6,11 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
public class DeviceConfiguration {
public static class DeviceConfigurationElement {

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
public class DeviceRules {
public String rcOnly;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.ArrayList;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
public class DiGraphEntry {
public String parent;

View File

@@ -6,11 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
public class Entity {
// from ObjectInfo

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;

View File

@@ -6,11 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
public class InventoryTag {
// from ObjectInfo

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
public class RRMAlgorithmDetails {
public String name;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;

View File

@@ -6,11 +6,11 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
public class Venue {
// from ObjectInfo

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.models;
package com.facebook.openwifi.cloudsdk.models.prov;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.rrm.models;
package com.facebook.openwifi.cloudsdk.models.prov.rrm;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.prov.rrm.models;
package com.facebook.openwifi.cloudsdk.models.prov.rrm;
public class Provider {
public String vendor;

View File

@@ -0,0 +1,6 @@
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSS} %-5p [%c{1}:%L] - %m%n

View File

@@ -6,15 +6,15 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral;
package com.facebook.openwifi.cloudsdk;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collections;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.Test;
public class UCentralUtilsTest {

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import static org.junit.jupiter.api.Assertions.assertEquals;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.ucentral.informationelement;
package com.facebook.openwifi.cloudsdk.ies;
import static org.junit.jupiter.api.Assertions.assertEquals;

4
owrrm/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/*.log*
/device_config.json
/settings.json
/topology.json

39
owrrm/README.md Normal file
View File

@@ -0,0 +1,39 @@
# OpenWiFi RRM Service
OpenWiFi uCentral-based radio resource management (RRM) service, providing a
cloud-based Wi-Fi RRM layer for APs running the OpenWiFi SDK.
This service collects data from OpenWiFi APs (e.g. Wi-Fi scans, stats,
capabilities) via the uCentral Gateway and Kafka, and integrates with the
OpenWiFi Provisioning service to perform optimization across configured
"venues". It pushes new device configuration parameters to APs after RRM
algorithms are run (manually or periodically).
See [IMPLEMENTATION.md](IMPLEMENTATION.md) for service architecture details and
[ALGORITHMS.md](ALGORITHMS.md) for descriptions of the RRM algorithms.
## Usage
```
$ java -jar openwifi-rrm.jar [-h]
```
To start the service, use the `run` command while providing configuration via
either environment variables (`--config-env`) or a static JSON file
(`--config-file`, default `settings.json`). The following data is *required*:
* Service configuration
* Env: `SERVICECONFIG_PRIVATEENDPOINT`, `SERVICECONFIG_PUBLICENDPOINT`
* JSON: `serviceConfig` structure
* Kafka broker URL
* Env: `KAFKACONFIG_BOOTSTRAPSERVER`
* JSON: `kafkaConfig` structure
* MySQL database credentials
* Env: `DATABASECONFIG_SERVER`, `DATABASECONFIG_USER`, `DATABASECONFIG_PASSWORD`
* JSON: `databaseConfig` structure
## OpenAPI
This service provides an OpenAPI HTTP interface on the port specified in the
service configuration (`moduleConfig.apiServerParams`). An auto-generated
OpenAPI 3.0 document is hosted at the endpoints `/openapi.{yaml,json}` and is
written to [openapi.yaml](openapi.yaml) during the Maven "compile" phase.
[JUnit 5]: https://junit.org/junit5/

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

143
owrrm/pom.xml Normal file
View File

@@ -0,0 +1,143 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>openwifi-rrm</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>com.facebook</groupId>
<artifactId>openwifi-base</artifactId>
<version>2.7.0</version>
</parent>
<properties>
<!-- Hack for static files located in root project -->
<myproject.root>${project.basedir}/..</myproject.root>
<mainClassName>com.facebook.openwifi.rrm.Launcher</mainClassName>
<appendVersionString></appendVersionString>
</properties>
<build>
<finalName>openwifi-rrm</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>src/main/resources-filtered</directory>
<filtering>true</filtering>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>${mainClassName}</Main-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.facebook</groupId>
<artifactId>openwifi-cloudsdk</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,160 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifi.rrm;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import spark.embeddedserver.jetty.JettyServerFactory;
import spark.utils.Assert;
/**
* Creates Jetty Server instances. Majority of the logic is taken from
* JettyServerFactory. The additional feature is that this class will actually
* set two connectors (original class doesn't set any connectors at all and
* leaves it up to the serivce start logic). Since we set two connectors here on
* the server, Spark uses the existing conectors instead of trying to spin up
* its own connectors. The other difference is that it uses a different
* ServerConnector constructor to avoid allocating additional threads that
* aren't necessary ({@link #makeConnector})
*
* @see spark.embeddedserver.jetty.EmbeddedJettyFactory
*/
public class CustomJettyServerFactory implements JettyServerFactory {
// normally this is set in EmbeddedJettyServer but since we create our own connectors here,
// we need the value here
private boolean trustForwardHeaders = true; // true by default
private final int internalPort;
private final int externalPort;
public CustomJettyServerFactory(int internalPort, int externalPort) {
this.internalPort = internalPort;
this.externalPort = externalPort;
}
public void setTrustForwardHeaders(boolean trustForwardHeaders) {
this.trustForwardHeaders = trustForwardHeaders;
}
/**
* This is basically
* spark.embeddedserver.jetty.SocketConnectorFactory.createSocketConnector,
* the only difference being that we use a different constructor for the
* Connector and that the private methods called are just inlined.
*/
public Connector makeConnector(
Server server,
String host,
int port,
boolean trustForwardHeaders
) {
Assert.notNull(server, "'server' must not be null");
Assert.notNull(host, "'host' must not be null");
// spark.embeddedserver.jetty.SocketConnectorFactory.createHttpConnectionFactory
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecureScheme("https");
if (trustForwardHeaders) {
httpConfig.addCustomizer(new ForwardedRequestCustomizer());
}
HttpConnectionFactory httpConnectionFactory =
new HttpConnectionFactory(httpConfig);
ServerConnector connector = new ServerConnector(
server,
0, // acceptors, don't allocate separate threads for acceptor
0, // selectors, use default number
httpConnectionFactory
);
// spark.embeddedserver.jetty.SocketConnectorFactory.initializeConnector
connector.setIdleTimeout(TimeUnit.HOURS.toMillis(1));
connector.setHost(host);
connector.setPort(port);
return connector;
}
/**
* Creates a Jetty server.
*
* @param maxThreads maxThreads
* @param minThreads minThreads
* @param threadTimeoutMillis threadTimeoutMillis
* @return a new jetty server instance
*/
@Override
public Server create(
int maxThreads,
int minThreads,
int threadTimeoutMillis
) {
Server server;
if (maxThreads > 0) {
int max = maxThreads;
int min = (minThreads > 0) ? minThreads : 8;
int idleTimeout =
(threadTimeoutMillis > 0) ? threadTimeoutMillis : 60000;
server = new Server(new QueuedThreadPool(max, min, idleTimeout));
} else {
server = new Server();
}
Connector internalConnector = null;
if (internalPort != -1) {
internalConnector = makeConnector(
server,
"0.0.0.0",
internalPort,
trustForwardHeaders
);
}
Connector externalConnector = null;
if (externalPort != -1) {
externalConnector = makeConnector(
server,
"0.0.0.0",
externalPort,
trustForwardHeaders
);
}
if (internalConnector == null) {
server.setConnectors(new Connector[] { externalConnector });
} else if (externalConnector == null) {
server.setConnectors(new Connector[] { internalConnector });
} else {
server.setConnectors(
new Connector[] { internalConnector, externalConnector }
);
}
return server;
}
/**
* Creates a Jetty server with supplied thread pool
* @param threadPool thread pool
* @return a new jetty server instance
*/
@Override
public Server create(ThreadPool threadPool) {
return threadPool != null ? new Server(threadPool) : new Server();
}
}

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.lang.reflect.Field;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.io.File;
import java.io.FileNotFoundException;
@@ -47,17 +47,17 @@ public class DeviceDataManager {
private final ReadWriteLock topologyLock = new ReentrantReadWriteLock();
/** Lock on {@link #deviceLayeredConfig}. */
private final ReadWriteLock deviceLayeredConfigLock =
public final ReadWriteLock deviceLayeredConfigLock =
new ReentrantReadWriteLock();
/** The current device topology. */
private DeviceTopology topology;
public DeviceTopology topology;
/** The current layered device config. */
private DeviceLayeredConfig deviceLayeredConfig;
public DeviceLayeredConfig deviceLayeredConfig;
/** The cached device configs (map of serial number to computed config). */
private Map<String, DeviceConfig> cachedDeviceConfigs =
public Map<String, DeviceConfig> cachedDeviceConfigs =
new ConcurrentHashMap<>();
/** Empty constructor without backing files (ex. for unit tests). */

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.util.Map;
import java.util.TreeMap;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.util.Set;
import java.util.TreeMap;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.io.File;
import java.io.FileWriter;
@@ -18,11 +18,10 @@ import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.mysql.DatabaseManager;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.UCentralKafkaConsumer;
import com.facebook.openwifirrm.ucentral.UCentralKafkaProducer;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaConsumer;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaProducer;
import com.facebook.openwifi.rrm.mysql.DatabaseManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -155,8 +154,7 @@ public class Launcher implements Callable<Integer> {
: DEFAULT_DEVICE_LAYERED_CONFIG_FILE
);
String serviceKey =
UCentralUtils.generateServiceKey(config.serviceConfig);
String serviceKey = Utils.generateServiceKey(config.serviceConfig);
// Instantiate clients
UCentralClient.verifySsl(config.uCentralConfig.verifySsl);
@@ -166,7 +164,9 @@ public class Launcher implements Callable<Integer> {
config.uCentralConfig.uCentralSecPublicEndpoint,
config.uCentralConfig.username,
config.uCentralConfig.password,
config.uCentralConfig.uCentralSocketParams
config.uCentralConfig.uCentralSocketParams.connectTimeoutMs,
config.uCentralConfig.uCentralSocketParams.socketTimeoutMs,
config.uCentralConfig.uCentralSocketParams.wifiScanTimeoutMs
);
UCentralKafkaConsumer consumer;
UCentralKafkaProducer producer;
@@ -265,7 +265,7 @@ public class Launcher implements Callable<Integer> {
.setPrettyPrinting()
.serializeNulls() // for here only!!
.create();
logger.info(gson.toJson(DeviceConfig.createDefault()));
System.out.println(gson.toJson(DeviceConfig.createDefault()));
return 0;
}

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.util.Arrays;
import java.util.List;
@@ -18,18 +18,18 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.modules.ApiServer;
import com.facebook.openwifirrm.modules.ConfigManager;
import com.facebook.openwifirrm.modules.DataCollector;
import com.facebook.openwifirrm.modules.Modeler;
import com.facebook.openwifirrm.modules.ProvMonitor;
import com.facebook.openwifirrm.modules.RRMScheduler;
import com.facebook.openwifirrm.mysql.DatabaseManager;
import com.facebook.openwifirrm.ucentral.KafkaRunner;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.UCentralKafkaConsumer;
import com.facebook.openwifirrm.ucentral.UCentralKafkaProducer;
import com.facebook.openwifirrm.ucentral.gw.models.SystemInfoResults;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.kafka.KafkaRunner;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaConsumer;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaProducer;
import com.facebook.openwifi.cloudsdk.models.gw.SystemInfoResults;
import com.facebook.openwifi.rrm.modules.ApiServer;
import com.facebook.openwifi.rrm.modules.ConfigManager;
import com.facebook.openwifi.rrm.modules.DataCollector;
import com.facebook.openwifi.rrm.modules.Modeler;
import com.facebook.openwifi.rrm.modules.ProvMonitor;
import com.facebook.openwifi.rrm.modules.RRMScheduler;
import com.facebook.openwifi.rrm.mysql.DatabaseManager;
/**
* RRM service runner.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.util.HashMap;
import java.util.Map;
@@ -14,17 +14,17 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.modules.ConfigManager;
import com.facebook.openwifirrm.modules.Modeler;
import com.facebook.openwifirrm.optimizers.channel.ChannelOptimizer;
import com.facebook.openwifirrm.optimizers.channel.LeastUsedChannelOptimizer;
import com.facebook.openwifirrm.optimizers.channel.RandomChannelInitializer;
import com.facebook.openwifirrm.optimizers.channel.UnmanagedApAwareChannelOptimizer;
import com.facebook.openwifirrm.optimizers.tpc.LocationBasedOptimalTPC;
import com.facebook.openwifirrm.optimizers.tpc.MeasurementBasedApApTPC;
import com.facebook.openwifirrm.optimizers.tpc.MeasurementBasedApClientTPC;
import com.facebook.openwifirrm.optimizers.tpc.RandomTxPowerInitializer;
import com.facebook.openwifirrm.optimizers.tpc.TPC;
import com.facebook.openwifi.rrm.modules.ConfigManager;
import com.facebook.openwifi.rrm.modules.Modeler;
import com.facebook.openwifi.rrm.optimizers.channel.ChannelOptimizer;
import com.facebook.openwifi.rrm.optimizers.channel.LeastUsedChannelOptimizer;
import com.facebook.openwifi.rrm.optimizers.channel.RandomChannelInitializer;
import com.facebook.openwifi.rrm.optimizers.channel.UnmanagedApAwareChannelOptimizer;
import com.facebook.openwifi.rrm.optimizers.tpc.LocationBasedOptimalTPC;
import com.facebook.openwifi.rrm.optimizers.tpc.MeasurementBasedApApTPC;
import com.facebook.openwifi.rrm.optimizers.tpc.MeasurementBasedApClientTPC;
import com.facebook.openwifi.rrm.optimizers.tpc.RandomTxPowerInitializer;
import com.facebook.openwifi.rrm.optimizers.tpc.TPC;
/**
* RRM algorithm model and utility methods.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.util.Map;
@@ -34,7 +34,7 @@ public class RRMConfig {
* Private endpoint for the RRM service
* ({@code SERVICECONFIG_PRIVATEENDPOINT})
*/
public String privateEndpoint = "http://owrrm.wlan.local:16789"; // see ApiServerParams.httpPort
public String privateEndpoint = "http://owrrm.wlan.local:16790"; // see ApiServerParams.internalHttpPort
/**
* Public endpoint for the RRM service
@@ -60,7 +60,7 @@ public class RRMConfig {
* ({@code SERVICECONFIG_VENDORREFERENCEURL})
*/
public String vendorReferenceUrl =
"https://github.com/Telecominfraproject/wlan-cloud-rrm/blob/main/ALGORITHMS.md";
"https://github.com/Telecominfraproject/wlan-cloud-rrm/blob/main/owrrm/ALGORITHMS.md";
}
/** Service configuration. */
@@ -309,6 +309,12 @@ public class RRMConfig {
* ({@code MODELERPARAMS_WIFISCANBUFFERSIZE})
*/
public int wifiScanBufferSize = 10;
/**
* Maximum rounds of States to store per device
* ({@code MODELERPARAMS_STATEBUFFERSIZE})
*/
public int stateBufferSize = 10;
}
/** Modeler parameters. */
@@ -319,10 +325,16 @@ public class RRMConfig {
*/
public class ApiServerParams {
/**
* The HTTP port to listen on, or -1 to disable
* ({@code APISERVERPARAMS_HTTPPORT})
* The HTTP port to listen on for internal traffic, or -1 to disable
* ({@code APISERVERPARAMS_INTERNALHTTPPORT})
*/
public int httpPort = 16789;
public int internalHttpPort = 16790;
/**
* The HTTP port to listen on for external traffic, or -1 to disable
* ({@code APISERVERPARAMS_EXTERNALHTTPPORT})
*/
public int externalHttpPort = 16789;
/**
* Comma-separated list of all allowed CORS domains (exact match
@@ -532,10 +544,16 @@ public class RRMConfig {
if ((v = env.get("MODELERPARAMS_WIFISCANBUFFERSIZE")) != null) {
modelerParams.wifiScanBufferSize = Integer.parseInt(v);
}
if ((v = env.get("MODELERPARAMS_STATEBUFFERSIZE")) != null) {
modelerParams.stateBufferSize = Integer.parseInt(v);
}
ModuleConfig.ApiServerParams apiServerParams =
config.moduleConfig.apiServerParams;
if ((v = env.get("APISERVERPARAMS_HTTPPORT")) != null) {
apiServerParams.httpPort = Integer.parseInt(v);
if ((v = env.get("APISERVERPARAMS_INTERNALHTTPPORT")) != null) {
apiServerParams.internalHttpPort = Integer.parseInt(v);
}
if ((v = env.get("APISERVERPARAMS_EXTERNALHTTPPORT")) != null) {
apiServerParams.externalHttpPort = Integer.parseInt(v);
}
if ((v = env.get("APISERVERPARAMS_CORSDOMAINLIST")) != null) {
apiServerParams.corsDomainList = v;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import java.io.File;
import java.io.FileNotFoundException;
@@ -16,6 +16,8 @@ import java.io.InputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
@@ -23,6 +25,8 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -31,6 +35,8 @@ import com.google.gson.GsonBuilder;
* Generic utility methods.
*/
public class Utils {
private static final Logger logger = LoggerFactory.getLogger(Utils.class);
/** Hex value array for use in {@link #longToMac(long)}. */
private static final char[] HEX_VALUES = "0123456789abcdef".toCharArray();
@@ -193,4 +199,19 @@ public class Utils {
public static <T> T deepCopy(T obj, Class<T> classOfT) {
return gson.fromJson(gson.toJson(obj), classOfT);
}
/** Generate the RRM service key. */
public static String generateServiceKey(
RRMConfig.ServiceConfig serviceConfig
) {
try {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
sha256.update(serviceConfig.publicEndpoint.getBytes());
sha256.update(serviceConfig.privateEndpoint.getBytes());
return Utils.bytesToHex(sha256.digest());
} catch (NoSuchAlgorithmException e) {
logger.error("Unable to generate service key", e);
return "";
}
}
}

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm;
package com.facebook.openwifi.rrm;
import picocli.CommandLine.IVersionProvider;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.aggregators;
package com.facebook.openwifi.rrm.aggregators;
/**
* Aggregates added values into one "aggregate" measure.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.aggregators;
package com.facebook.openwifi.rrm.aggregators;
/**
* Tracks the mean of all added values. If no values are added, the mean is 0.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.net.InetAddress;
import java.net.URI;
@@ -35,31 +35,33 @@ import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.DeviceLayeredConfig;
import com.facebook.openwifirrm.DeviceTopology;
import com.facebook.openwifirrm.RRMAlgorithm;
import com.facebook.openwifirrm.RRMConfig.ModuleConfig.ApiServerParams;
import com.facebook.openwifirrm.RRMConfig.ServiceConfig;
import com.facebook.openwifirrm.Utils.LruCache;
import com.facebook.openwifirrm.VersionProvider;
import com.facebook.openwifirrm.optimizers.channel.LeastUsedChannelOptimizer;
import com.facebook.openwifirrm.optimizers.channel.RandomChannelInitializer;
import com.facebook.openwifirrm.optimizers.channel.UnmanagedApAwareChannelOptimizer;
import com.facebook.openwifirrm.optimizers.tpc.LocationBasedOptimalTPC;
import com.facebook.openwifirrm.optimizers.tpc.MeasurementBasedApApTPC;
import com.facebook.openwifirrm.optimizers.tpc.MeasurementBasedApClientTPC;
import com.facebook.openwifirrm.optimizers.tpc.RandomTxPowerInitializer;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.gw.models.SystemInfoResults;
import com.facebook.openwifirrm.ucentral.gw.models.TokenValidationResult;
import com.facebook.openwifirrm.ucentral.prov.rrm.models.Algorithm;
import com.facebook.openwifirrm.ucentral.prov.rrm.models.Provider;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.models.gw.SystemInfoResults;
import com.facebook.openwifi.cloudsdk.models.gw.TokenValidationResult;
import com.facebook.openwifi.cloudsdk.models.prov.rrm.Algorithm;
import com.facebook.openwifi.cloudsdk.models.prov.rrm.Provider;
import com.facebook.openwifi.rrm.CustomJettyServerFactory;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.DeviceLayeredConfig;
import com.facebook.openwifi.rrm.DeviceTopology;
import com.facebook.openwifi.rrm.RRMAlgorithm;
import com.facebook.openwifi.rrm.Utils;
import com.facebook.openwifi.rrm.VersionProvider;
import com.facebook.openwifi.rrm.RRMConfig.ServiceConfig;
import com.facebook.openwifi.rrm.RRMConfig.ModuleConfig.ApiServerParams;
import com.facebook.openwifi.rrm.Utils.LruCache;
import com.facebook.openwifi.rrm.optimizers.channel.LeastUsedChannelOptimizer;
import com.facebook.openwifi.rrm.optimizers.channel.RandomChannelInitializer;
import com.facebook.openwifi.rrm.optimizers.channel.UnmanagedApAwareChannelOptimizer;
import com.facebook.openwifi.rrm.optimizers.tpc.LocationBasedOptimalTPC;
import com.facebook.openwifi.rrm.optimizers.tpc.MeasurementBasedApApTPC;
import com.facebook.openwifi.rrm.optimizers.tpc.MeasurementBasedApClientTPC;
import com.facebook.openwifi.rrm.optimizers.tpc.RandomTxPowerInitializer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.openjdk.jol.info.GraphLayout;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.jaxrs2.Reader;
@@ -81,7 +83,9 @@ import io.swagger.v3.oas.models.OpenAPI;
import spark.Request;
import spark.Response;
import spark.Route;
import spark.Spark;
import spark.Service;
import spark.embeddedserver.EmbeddedServers;
import spark.embeddedserver.jetty.EmbeddedJettyFactory;
/**
* HTTP API server.
@@ -110,6 +114,27 @@ public class ApiServer implements Runnable {
private static final Logger logger =
LoggerFactory.getLogger(ApiServer.class);
/**
* This is the identifier for the server factory that Spark should use. This
* particular identifier points to the custom factory that we register to
* enable running multiple ports on one service.
*
* @see #run()
*/
private static final String SPARK_EMBEDDED_SERVER_IDENTIFIER =
ApiServer.class.getName();
/**
* The Spark service instance. Normally, you would use the static methods on
* Spark, but since we need to spin up multiple instances of Spark for testing,
* we choose to go with instantiating the service ourselves. There is really no
* difference except with the static method, Spark calls ignite and holds a
* singleton instance for us.
*
* @see Spark
*/
private final Service service;
/** The module parameters. */
private final ApiServerParams params;
@@ -164,9 +189,10 @@ public class ApiServer implements Runnable {
UCentralClient client,
RRMScheduler scheduler
) {
this.service = Service.ignite();
this.params = params;
this.serviceConfig = serviceConfig;
this.serviceKey = UCentralUtils.generateServiceKey(serviceConfig);
this.serviceKey = Utils.generateServiceKey(serviceConfig);
this.deviceDataManager = deviceDataManager;
this.configManager = configManager;
this.modeler = modeler;
@@ -194,64 +220,117 @@ public class ApiServer implements Runnable {
return ret;
}
/**
* Block until initialization finishes. Just calls the method on the
* underlying service.
*/
public void awaitInitialization() {
service.awaitInitialization();
}
@Override
public void run() {
this.startTimeMs = System.currentTimeMillis();
if (params.httpPort == -1) {
if (params.internalHttpPort == -1 && params.externalHttpPort == -1) {
logger.info("API server is disabled.");
return;
} else if (params.internalHttpPort == -1) {
logger.info("Internal API server is disabled");
} else if (params.externalHttpPort == -1) {
logger.info("External API server is disabled");
}
if (params.internalHttpPort == params.externalHttpPort) {
logger.error(
"Internal and external port cannot be the same - not starting API server"
);
return;
}
Spark.port(params.httpPort);
EmbeddedServers.add(
SPARK_EMBEDDED_SERVER_IDENTIFIER,
new EmbeddedJettyFactory(
new CustomJettyServerFactory(
params.internalHttpPort,
params.externalHttpPort
)
)
);
// use the embedded server factory added above, this is required so that we
// don't mess up the default factory which can and will be used for
// additional Spark services in testing
service.embeddedServerIdentifier(SPARK_EMBEDDED_SERVER_IDENTIFIER);
// Usually you would call this with an actual port and Spark would spin up a
// port on it. However, since we're putting our own connectors in so that we
// can use two ports and Spark has logic to use connectors that already exist
// so it doesn't matter what port we pass in here as long as it's not one of
// the actual ports we're using (Spark has some weird logic where it still
// tries to bind to the port).
// @see EmbeddedJettyServer
service.port(0);
// Configure API docs hosting
Spark.staticFiles.location("/public");
Spark.get("/openapi.yaml", this::getOpenApiYaml);
Spark.get("/openapi.json", this::getOpenApiJson);
service.staticFiles.location("/public");
service.get("/openapi.yaml", this::getOpenApiYaml);
service.get("/openapi.json", this::getOpenApiJson);
// Install routes
Spark.before(this::beforeFilter);
Spark.after(this::afterFilter);
Spark.options("/*", this::options);
Spark.get("/api/v1/system", new SystemEndpoint());
Spark.post("/api/v1/system", new SetSystemEndpoint());
Spark.get("/api/v1/provider", new ProviderEndpoint());
Spark.get("/api/v1/algorithms", new AlgorithmsEndpoint());
Spark.put("/api/v1/runRRM", new RunRRMEndpoint());
Spark.get("/api/v1/getTopology", new GetTopologyEndpoint());
Spark.post("/api/v1/setTopology", new SetTopologyEndpoint());
Spark.get(
service.before(this::beforeFilter);
service.after(this::afterFilter);
service.options("/*", this::options);
service.get("/api/v1/system", new SystemEndpoint());
service.post("/api/v1/system", new SetSystemEndpoint());
service.get("/api/v1/provider", new ProviderEndpoint());
service.get("/api/v1/algorithms", new AlgorithmsEndpoint());
service.put("/api/v1/runRRM", new RunRRMEndpoint());
service.get("/api/v1/getTopology", new GetTopologyEndpoint());
service.post("/api/v1/setTopology", new SetTopologyEndpoint());
service.get(
"/api/v1/getDeviceLayeredConfig",
new GetDeviceLayeredConfigEndpoint()
);
Spark.get("/api/v1/getDeviceConfig", new GetDeviceConfigEndpoint());
Spark.post(
service.get("/api/v1/getDeviceConfig", new GetDeviceConfigEndpoint());
service.post(
"/api/v1/setDeviceNetworkConfig",
new SetDeviceNetworkConfigEndpoint()
);
Spark.post(
service.post(
"/api/v1/setDeviceZoneConfig",
new SetDeviceZoneConfigEndpoint()
);
Spark.post(
service.post(
"/api/v1/setDeviceApConfig",
new SetDeviceApConfigEndpoint()
);
Spark.post(
service.post(
"/api/v1/modifyDeviceApConfig",
new ModifyDeviceApConfigEndpoint()
);
Spark.get("/api/v1/currentModel", new GetCurrentModelEndpoint());
Spark.get("/api/v1/optimizeChannel", new OptimizeChannelEndpoint());
Spark.get("/api/v1/optimizeTxPower", new OptimizeTxPowerEndpoint());
service.get("/api/v1/currentModel", new GetCurrentModelEndpoint());
service.get("/api/v1/optimizeChannel", new OptimizeChannelEndpoint());
service.get("/api/v1/optimizeTxPower", new OptimizeTxPowerEndpoint());
service.get("/api/v1/memory", new MemoryEndpoint(this));
logger.info("API server listening on HTTP port {}", params.httpPort);
logger.info(
"API server listening for HTTP internal on port {} and external on port {}",
params.internalHttpPort,
params.externalHttpPort
);
}
/** Stop the server. */
public void shutdown() {
Spark.stop();
service.stop();
}
/**
* Block until stop finishes. Just calls the method on the underlying service.
*/
public void awaitStop() {
service.awaitStop();
}
/** Reconstructs a URL. */
@@ -269,15 +348,17 @@ public class ApiServer implements Runnable {
* HTTP 403 response and return false.
*/
private boolean performOpenWifiAuth(Request request, Response response) {
// TODO check if request came from internal endpoint
boolean internal = true;
String internalName = request.headers("X-INTERNAL-NAME");
if (internal && internalName != null) {
// Internal request, validate "X-API-KEY"
String apiKey = request.headers("X-API-KEY");
if (apiKey != null && apiKey.equals(serviceKey)) {
// auth success
return true;
int port = request.port();
boolean internal = port > 0 && port == params.internalHttpPort;
if (internal) {
String internalName = request.headers("X-INTERNAL-NAME");
if (internalName != null) {
// Internal request, validate "X-API-KEY"
String apiKey = request.headers("X-API-KEY");
if (apiKey != null && apiKey.equals(serviceKey)) {
// auth success
return true;
}
}
} else {
// External request, validate token:
@@ -297,7 +378,7 @@ public class ApiServer implements Runnable {
}
// auth failure
Spark.halt(403, "Forbidden");
service.halt(403, "Forbidden");
return false;
}
@@ -325,10 +406,11 @@ public class ApiServer implements Runnable {
private void beforeFilter(Request request, Response response) {
// Log requests
logger.debug(
"[{}] {} {}",
"[{}] {} {} on port {}",
request.ip(),
request.requestMethod(),
getFullUrl(request.pathInfo(), request.queryString())
getFullUrl(request.pathInfo(), request.queryString()),
request.port()
);
// Remove "Server: Jetty" header
@@ -1280,6 +1362,91 @@ public class ApiServer implements Runnable {
}
}
@Path("/api/v1/memory")
public class MemoryEndpoint implements Route {
private final ApiServer apiServer;
MemoryEndpoint(ApiServer server) {
this.apiServer = server;
}
@Override
public String handle(Request request, Response response) {
String type = request.queryParamOrDefault("type", "");
String view = request.queryParamOrDefault("view", "footprint");
java.util.function.Function<GraphLayout, String> fn = (GraphLayout graph) -> {
return view.equals("footprint") ? graph.toFootprint() : graph.toPrintable();
};
String result;
switch (type) {
case "modeler.dataModel":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.dataModel));
break;
case "modeler.dataModel.latestWifiScans":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.dataModel.latestWifiScans));
break;
case "modeler.dataModel.latestStates":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.dataModel.latestStates));
break;
case "modeler.dataModel.latestDeviceStatusRadios":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.dataModel.latestDeviceStatusRadios));
break;
case "modeler.deviceDataManager":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.deviceDataManager));
break;
case "modeler.deviceDataManager.topology":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.deviceDataManager.topology));
break;
case "modeler.deviceDataManager.deviceLayeredConfig":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.deviceDataManager.deviceLayeredConfig));
break;
case "modeler.deviceDataManager.cachedDeviceConfigs":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.deviceDataManager.cachedDeviceConfigs));
break;
case "modeler.dataModel.latestDeviceCapabilities":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler.dataModel.latestDeviceCapabilities));
case "modeler":
result = fn.apply(GraphLayout.parseInstance(apiServer.modeler));
break;
case "configManager.deviceDataMap":
result = fn.apply(GraphLayout.parseInstance(apiServer.configManager.deviceDataMap));
break;
case "configManager":
result = fn.apply(GraphLayout.parseInstance(apiServer.configManager));
break;
case "scheduler":
result = fn.apply(GraphLayout.parseInstance(apiServer.scheduler));
break;
case "deviceDataManager":
result = fn.apply(GraphLayout.parseInstance(apiServer.deviceDataManager));
break;
case "":
default:
result = GraphLayout.parseInstance(apiServer).toFootprint();
break;
}
logger.info("MEMORY RESPONSE: \n{}", result);
return result;
}
}
@Path("/api/v1/optimizeTxPower")
public class OptimizeTxPowerEndpoint implements Route {
// Hack for use in @ApiResponse -> @Content -> @Schema

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.util.ArrayList;
import java.util.HashMap;
@@ -21,13 +21,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.RRMConfig.ModuleConfig.ConfigManagerParams;
import com.facebook.openwifirrm.ucentral.UCentralApConfiguration;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceWithStatus;
import com.facebook.openwifi.cloudsdk.UCentralApConfiguration;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.UCentralUtils;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceWithStatus;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.RRMConfig.ModuleConfig.ConfigManagerParams;
/**
* Device configuration manager module.
@@ -46,7 +46,7 @@ public class ConfigManager implements Runnable {
private final UCentralClient client;
/** Runtime per-device data. */
private class DeviceData {
public class DeviceData {
/** Last received device config. */
public UCentralApConfiguration config;
@@ -55,7 +55,7 @@ public class ConfigManager implements Runnable {
}
/** Map from device serial number to runtime data. */
private Map<String, DeviceData> deviceDataMap = new TreeMap<>();
public Map<String, DeviceData> deviceDataMap = new TreeMap<>();
/** The main thread reference (i.e. where {@link #run()} is invoked). */
private Thread mainThread;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -23,22 +23,22 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.RRMConfig.ModuleConfig.DataCollectorParams;
import com.facebook.openwifirrm.Utils;
import com.facebook.openwifirrm.mysql.DatabaseManager;
import com.facebook.openwifirrm.mysql.StateRecord;
import com.facebook.openwifirrm.ucentral.UCentralApConfiguration;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.UCentralKafkaConsumer;
import com.facebook.openwifirrm.ucentral.UCentralKafkaConsumer.KafkaRecord;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.gw.models.CommandInfo;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceCapabilities;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceWithStatus;
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
import com.facebook.openwifi.cloudsdk.UCentralApConfiguration;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.UCentralUtils;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaConsumer;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaConsumer.KafkaRecord;
import com.facebook.openwifi.cloudsdk.models.gw.CommandInfo;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceCapabilities;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceWithStatus;
import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.Utils;
import com.facebook.openwifi.rrm.RRMConfig.ModuleConfig.DataCollectorParams;
import com.facebook.openwifi.rrm.mysql.DatabaseManager;
import com.facebook.openwifi.rrm.mysql.StateRecord;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.util.LinkedList;
import java.util.List;
@@ -20,21 +20,21 @@ import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.RRMConfig.ModuleConfig.ModelerParams;
import com.facebook.openwifirrm.Utils;
import com.facebook.openwifirrm.ucentral.UCentralApConfiguration;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.UCentralKafkaConsumer;
import com.facebook.openwifirrm.ucentral.UCentralKafkaConsumer.KafkaRecord;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceCapabilities;
import com.facebook.openwifirrm.ucentral.gw.models.DeviceWithStatus;
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
import com.facebook.openwifirrm.ucentral.gw.models.StatisticsRecords;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifi.cloudsdk.UCentralApConfiguration;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.UCentralUtils;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaConsumer;
import com.facebook.openwifi.cloudsdk.kafka.UCentralKafkaConsumer.KafkaRecord;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceCapabilities;
import com.facebook.openwifi.cloudsdk.models.gw.DeviceWithStatus;
import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
import com.facebook.openwifi.cloudsdk.models.gw.StatisticsRecords;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.RRMConfig.ModuleConfig.ModelerParams;
import com.facebook.openwifi.rrm.Utils;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@@ -50,7 +50,7 @@ public class Modeler implements Runnable {
private final ModelerParams params;
/** The device data manager. */
private final DeviceDataManager deviceDataManager;
public final DeviceDataManager deviceDataManager;
/** The uCentral client instance. */
private final UCentralClient client;
@@ -74,7 +74,7 @@ public class Modeler implements Runnable {
}
/** The blocking data queue. */
private final BlockingQueue<InputData> dataQueue =
public final BlockingQueue<InputData> dataQueue =
new LinkedBlockingQueue<>();
/** Data model representation. */
@@ -93,8 +93,9 @@ public class Modeler implements Runnable {
public Map<String, List<List<WifiScanEntry>>> latestWifiScans =
new ConcurrentHashMap<>();
/** List of latest state per device. */
public Map<String, State> latestState = new ConcurrentHashMap<>();
/** List of latest states per device. */
public Map<String, List<State>> latestStates =
new ConcurrentHashMap<>();
/** List of radio info per device. */
public Map<String, JsonArray> latestDeviceStatusRadios =
@@ -267,7 +268,10 @@ public class Modeler implements Runnable {
if (state != null) {
try {
State stateModel = gson.fromJson(state, State.class);
dataModel.latestState.put(device.serialNumber, stateModel);
dataModel.latestStates.computeIfAbsent(
device.serialNumber,
k -> new LinkedList<>()
).add(stateModel);
logger.debug(
"Device {}: added initial state from uCentralGw",
device.serialNumber
@@ -299,8 +303,17 @@ public class Modeler implements Runnable {
if (state != null) {
try {
State stateModel = gson.fromJson(state, State.class);
dataModel.latestState
.put(record.serialNumber, stateModel);
List<State> latestStatesList = dataModel.latestStates
.computeIfAbsent(
record.serialNumber,
k -> new LinkedList<>()
);
while (
latestStatesList.size() >= params.stateBufferSize
) {
latestStatesList.remove(0);
}
latestStatesList.add(stateModel);
stateUpdates.add(record.serialNumber);
} catch (JsonSyntaxException e) {
logger.error(
@@ -423,7 +436,7 @@ public class Modeler implements Runnable {
logger.debug("Removed some wifi scan entries from data model");
}
if (
dataModel.latestState.entrySet()
dataModel.latestStates.entrySet()
.removeIf(e -> !isRRMEnabled(e.getKey()))
) {
logger.debug("Removed some state entries from data model");

View File

@@ -6,24 +6,33 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.aggregators.Aggregator;
import com.facebook.openwifirrm.aggregators.MeanAggregator;
import com.facebook.openwifirrm.modules.Modeler.DataModel;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.informationelement.HTOperation;
import com.facebook.openwifirrm.ucentral.informationelement.VHTOperation;
import com.facebook.openwifi.cloudsdk.AggregatedState;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.ies.HTOperation;
import com.facebook.openwifi.cloudsdk.ies.VHTOperation;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.facebook.openwifi.cloudsdk.models.ap.State.Interface;
import com.facebook.openwifi.cloudsdk.models.ap.State.Interface.SSID;
import com.facebook.openwifi.cloudsdk.models.ap.State.Interface.SSID.Association;
import com.facebook.openwifi.rrm.aggregators.Aggregator;
import com.facebook.openwifi.rrm.aggregators.MeanAggregator;
import com.facebook.openwifi.rrm.modules.Modeler.DataModel;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* Modeler utilities.
@@ -291,7 +300,7 @@ public class ModelerUtils {
/**
* Compute aggregated wifiscans using a given reference time.
*
* @see #getAggregatedWifiScans(com.facebook.openwifirrm.modules.Modeler.DataModel,
* @see #getAggregatedWifiScans(com.facebook.openwifi.rrm.modules.Modeler.DataModel,
* long, Aggregator)
*/
public static Map<String, Map<String, WifiScanEntry>> getAggregatedWifiScans(
@@ -381,4 +390,196 @@ public class ModelerUtils {
}
return aggregatedWifiScans;
}
/**
* This method converts the input State info to an AggregatedState
* and adds it to the bssidToAggregatedStates map. If the bssid/station
* of the input State does not exist in the map, create a new
* AggregatedState list. If the bssid/station of the input State exists,
* then convert State to AggregatedState and check if there exits an
* AggregatedState of the same radio. If there does, append the value
* of aggregation field to the existing AggregatedState, if not, create
* a new AggregatedState and add it to the list.
*
* @param bssidToAggregatedStates map from bssid/station to a list of AggregatedState
* @param state the state that is to be added
*/
static void addStateToAggregation(
Map<String, List<AggregatedState>> bssidToAggregatedStates,
State state
) {
for (Interface stateInterface : state.interfaces) {
if (stateInterface.ssids == null) {
continue;
}
for (SSID ssid : stateInterface.ssids) {
Map<String, Integer> radioInfo = new HashMap<>();
radioInfo.put("channel", ssid.radio.get("channel").getAsInt());
radioInfo.put(
"channel_width",
ssid.radio.get("channel_width").getAsInt()
);
radioInfo
.put("tx_power", ssid.radio.get("tx_power").getAsInt());
for (Association association : ssid.associations) {
if (association == null) {
continue;
}
String key = getBssidStationKeyPair(
association.bssid,
association.station
);
List<AggregatedState> aggregatedStates =
bssidToAggregatedStates
.computeIfAbsent(key, k -> new ArrayList<>());
AggregatedState aggState =
new AggregatedState(association, radioInfo);
/**
* Indicate if the aggState can be merged into some old AggregatedState.
* If true, it will be merged by appending its mcs/rssi field to the old one.
* If false, it will be added to the list aggregatedStates.
*/
boolean canBeMergedToOldAggregatedState = false;
for (
AggregatedState oldAggregatedState : aggregatedStates
) {
if (oldAggregatedState.add(aggState)) {
canBeMergedToOldAggregatedState = true;
break;
}
}
if (!canBeMergedToOldAggregatedState) {
aggregatedStates.add(aggState);
}
bssidToAggregatedStates.put(key, aggregatedStates);
}
}
}
}
/**
* This method aggregates States by bssid/station key pair and radio info.
* if two States of the same bssid/station match in channel, channel width and tx_power
* need to be aggregated to one {@code AggregatedState}. Currently only mcs and
* rssi fields are being aggregated. They are of {@code List<Integer>} type in AggregatedState,
* which list all the values over the time.
*
* @param dataModel the data model which includes the latest recorded States
* @param obsoletionPeriodMs the maximum amount of time (in milliseconds) it
* is worth aggregating over, starting from the
* most recent States and working backwards in time.
* A State exactly {@code obsoletionPeriodMs} ms earlier
* than the most recent State is considered non-obsolete
* (i.e., the "non-obsolete" window is inclusive).
* Must be non-negative.
* @param refTimeMs the reference time were passed to make testing easier
* @return map from serial number to a map from bssid_station String pair to a list of AggregatedState
*/
public static Map<String, Map<String, List<AggregatedState>>> getAggregatedStates(
Modeler.DataModel dataModel,
long obsoletionPeriodMs,
long refTimeMs
) {
if (obsoletionPeriodMs < 0) {
throw new IllegalArgumentException(
"obsoletionPeriodMs must be non-negative."
);
}
Map<String, Map<String, List<AggregatedState>>> aggregatedStates =
new HashMap<>();
for (
Map.Entry<String, List<State>> deviceToStateList : dataModel.latestStates
.entrySet()
) {
String serialNumber = deviceToStateList.getKey();
List<State> states = deviceToStateList.getValue();
if (states.isEmpty()) {
continue;
}
/**
* Sort in reverse chronological order. Sorting is done just in case the
* States in the original list are not chronological already - although
* they are inserted chronologically, perhaps latency, synchronization, etc.
*/
states.sort(
(state1, state2) -> -Long.compare(state1.unit.localtime, state2.unit.localtime)
);
Map<String, List<AggregatedState>> bssidToAggregatedStates =
aggregatedStates
.computeIfAbsent(serialNumber, k -> new HashMap<>());
for (State state : states) {
if (refTimeMs - state.unit.localtime > obsoletionPeriodMs) {
// discard obsolete entries
break;
}
addStateToAggregation(bssidToAggregatedStates, state);
}
}
return aggregatedStates;
}
/**
* This method gets the most recent State from latestStates per device.
*
* @param latestStates list of latest States per device
* @return map from device String to latest State
*/
public static Map<String, State> getLatestState(
Map<String, List<State>> latestStates
) {
Map<String, State> latestState = new ConcurrentHashMap<>();
for (
Map.Entry<String, List<State>> stateEntry : latestStates.entrySet()
) {
String key = stateEntry.getKey();
List<State> value = stateEntry.getValue();
if (value.isEmpty()) {
latestState.put(key, null);
} else {
latestState.put(key, value.get(value.size() - 1));
}
}
return latestState;
}
/** Create a key pair consisted of bssid and station string */
public static String getBssidStationKeyPair(String bssid, String station) {
return String.format(
"bssid: %s, station: %s",
bssid,
station
);
}
/** Return the radio's band, or null if band cannot be found */
public static String getBand(
State.Radio radio,
JsonObject deviceCapability
) {
if (radio.phy == null) {
return null;
}
JsonElement radioCapabilityElement = deviceCapability.get(radio.phy);
if (radioCapabilityElement == null) {
return null;
}
JsonObject radioCapability = radioCapabilityElement.getAsJsonObject();
JsonElement bandsElement = radioCapability.get("band");
if (bandsElement == null) {
return null;
}
JsonArray bands = bandsElement.getAsJsonArray();
if (bands.isEmpty()) {
return null;
}
return bands.get(0).getAsString();
}
}

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.util.Arrays;
import java.util.HashMap;
@@ -18,19 +18,19 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.DeviceTopology;
import com.facebook.openwifirrm.RRMAlgorithm;
import com.facebook.openwifirrm.RRMConfig.ModuleConfig.ProvMonitorParams;
import com.facebook.openwifirrm.RRMSchedule;
import com.facebook.openwifirrm.ucentral.UCentralClient;
import com.facebook.openwifirrm.ucentral.prov.models.InventoryTag;
import com.facebook.openwifirrm.ucentral.prov.models.InventoryTagList;
import com.facebook.openwifirrm.ucentral.prov.models.RRMDetails;
import com.facebook.openwifirrm.ucentral.prov.models.SerialNumberList;
import com.facebook.openwifirrm.ucentral.prov.models.Venue;
import com.facebook.openwifirrm.ucentral.prov.models.VenueList;
import com.facebook.openwifi.cloudsdk.UCentralClient;
import com.facebook.openwifi.cloudsdk.models.prov.InventoryTag;
import com.facebook.openwifi.cloudsdk.models.prov.InventoryTagList;
import com.facebook.openwifi.cloudsdk.models.prov.RRMDetails;
import com.facebook.openwifi.cloudsdk.models.prov.SerialNumberList;
import com.facebook.openwifi.cloudsdk.models.prov.Venue;
import com.facebook.openwifi.cloudsdk.models.prov.VenueList;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.DeviceTopology;
import com.facebook.openwifi.rrm.RRMAlgorithm;
import com.facebook.openwifi.rrm.RRMSchedule;
import com.facebook.openwifi.rrm.RRMConfig.ModuleConfig.ProvMonitorParams;
/**
* owprov monitor module.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.modules;
package com.facebook.openwifi.rrm.modules;
import java.text.ParseException;
import java.util.Arrays;
@@ -32,11 +32,11 @@ import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.RRMAlgorithm;
import com.facebook.openwifirrm.RRMSchedule;
import com.facebook.openwifirrm.RRMConfig.ModuleConfig.RRMSchedulerParams;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.RRMAlgorithm;
import com.facebook.openwifi.rrm.RRMSchedule;
import com.facebook.openwifi.rrm.RRMConfig.ModuleConfig.RRMSchedulerParams;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.mysql;
package com.facebook.openwifi.rrm.mysql;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -26,9 +26,9 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.Utils;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.facebook.openwifi.rrm.Utils;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.mysql;
package com.facebook.openwifi.rrm.mysql;
/**
* Representation of a record in the "state" table.

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.optimizers.channel;
package com.facebook.openwifi.rrm.optimizers.channel;
import java.util.ArrayList;
import java.util.Arrays;
@@ -18,16 +18,18 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceConfig;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.modules.ConfigManager;
import com.facebook.openwifirrm.modules.Modeler.DataModel;
import com.facebook.openwifirrm.ucentral.UCentralConstants;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.informationelement.HTOperation;
import com.facebook.openwifirrm.ucentral.informationelement.VHTOperation;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifi.cloudsdk.UCentralConstants;
import com.facebook.openwifi.cloudsdk.UCentralUtils;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.ies.HTOperation;
import com.facebook.openwifi.cloudsdk.ies.VHTOperation;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.facebook.openwifi.rrm.DeviceConfig;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.modules.ConfigManager;
import com.facebook.openwifi.rrm.modules.Modeler.DataModel;
import com.facebook.openwifi.rrm.modules.ModelerUtils;
import com.google.gson.JsonObject;
/**
* Channel optimizer base class.
@@ -39,24 +41,6 @@ public abstract class ChannelOptimizer {
/** Minimum supported channel width (MHz), inclusive. */
public static final int MIN_CHANNEL_WIDTH = 20;
/** List of available channels per band for use. */
public static final Map<String, List<Integer>> AVAILABLE_CHANNELS_BAND =
new HashMap<>();
static {
AVAILABLE_CHANNELS_BAND.put(
UCentralConstants.BAND_5G,
Collections.unmodifiableList(
Arrays.asList(36, 40, 44, 48, 149, 153, 157, 161, 165)
)
);
AVAILABLE_CHANNELS_BAND.put(
UCentralConstants.BAND_2G,
Collections.unmodifiableList(
Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
)
);
}
/** Map of channel width (MHz) to available (primary) channels */
protected static final Map<Integer, List<Integer>> AVAILABLE_CHANNELS_WIDTH =
new HashMap<>();
@@ -154,7 +138,7 @@ public abstract class ChannelOptimizer {
// Remove model entries not in the given zone
this.model.latestWifiScans.keySet()
.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
this.model.latestState.keySet()
this.model.latestStates.keySet()
.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
this.model.latestDeviceStatusRadios.keySet()
.removeIf(serialNumber -> !deviceConfigs.containsKey(serialNumber));
@@ -197,7 +181,7 @@ public abstract class ChannelOptimizer {
String vhtOper
) {
if (
AVAILABLE_CHANNELS_BAND.get(UCentralConstants.BAND_2G)
UCentralUtils.AVAILABLE_CHANNELS_BAND.get(UCentralConstants.BAND_2G)
.contains(channel)
) {
// 2.4G, it only supports 20 MHz
@@ -316,25 +300,28 @@ public abstract class ChannelOptimizer {
List<WifiScanEntry> scanRespsFiltered =
new ArrayList<WifiScanEntry>();
for (WifiScanEntry entry : scanResps) {
if (UCentralUtils.isChannelInBand(entry.channel, band)) {
int channelWidth = getChannelWidthFromWiFiScan(
final String entryBand = UCentralUtils
.freqToBand(entry.frequency);
if (entryBand == null || !entryBand.equals(band)) {
continue;
}
int channelWidth = getChannelWidthFromWiFiScan(
entry.channel,
entry.ht_oper,
entry.vht_oper
);
int primaryChannel =
getPrimaryChannel(entry.channel, channelWidth);
List<Integer> coveredChannels =
getCoveredChannels(
entry.channel,
entry.ht_oper,
entry.vht_oper
primaryChannel,
channelWidth
);
int primaryChannel =
getPrimaryChannel(entry.channel, channelWidth);
List<Integer> coveredChannels =
getCoveredChannels(
entry.channel,
primaryChannel,
channelWidth
);
for (Integer newChannel : coveredChannels) {
WifiScanEntry newEntry = new WifiScanEntry(entry);
newEntry.channel = newChannel;
scanRespsFiltered.add(newEntry);
}
for (Integer newChannel : coveredChannels) {
WifiScanEntry newEntry = new WifiScanEntry(entry);
newEntry.channel = newChannel;
scanRespsFiltered.add(newEntry);
}
}
@@ -362,6 +349,7 @@ public abstract class ChannelOptimizer {
* @param band the operational band (e.g., "2G")
* @param serialNumber the device's serial number
* @param state the latest state of all the devices
* @param latestDeviceCapabilities latest device capabilities
* @return the current channel and channel width (MHz) of the device in the
* given band; returns a current channel of 0 if no channel in the given
* band is found.
@@ -369,7 +357,8 @@ public abstract class ChannelOptimizer {
protected static int[] getCurrentChannel(
String band,
String serialNumber,
State state
State state,
Map<String, JsonObject> latestDeviceCapabilities
) {
int currentChannel = 0;
int currentChannelWidth = MIN_CHANNEL_WIDTH;
@@ -379,27 +368,40 @@ public abstract class ChannelOptimizer {
radioIndex < state.radios.length;
radioIndex++
) {
int tempChannel = state.radios[radioIndex].channel;
if (UCentralUtils.isChannelInBand(tempChannel, band)) {
currentChannel = tempChannel;
// treat as two separate 80MHz channel and only assign to one
// TODO: support 80p80 properly
Integer parsedChannelWidth = UCentralUtils
.parseChannelWidth(
state.radios[radioIndex].channel_width,
true
);
if (parsedChannelWidth != null) {
currentChannelWidth = parsedChannelWidth;
break;
}
logger.error(
"Invalid channel width {}",
state.radios[radioIndex].channel_width
);
State.Radio radio = state.radios[radioIndex];
// check if radio is in band of interest
JsonObject deviceCapability =
latestDeviceCapabilities.get(serialNumber);
if (deviceCapability == null) {
continue;
}
final String radioBand = ModelerUtils.getBand(
radio,
deviceCapability
);
if (radioBand == null || !radioBand.equals(band)) {
continue;
}
int tempChannel = radio.channel;
currentChannel = tempChannel;
// treat as two separate 80MHz channel and only assign to one
// TODO: support 80p80 properly
Integer parsedChannelWidth = UCentralUtils
.parseChannelWidth(
radio.channel_width,
true
);
if (parsedChannelWidth != null) {
currentChannelWidth = parsedChannelWidth;
break;
}
logger.error(
"Invalid channel width {}",
radio.channel_width
);
continue;
}
return new int[] { currentChannel, currentChannelWidth };
}

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.optimizers.channel;
package com.facebook.openwifi.rrm.optimizers.channel;
import java.util.ArrayList;
import java.util.HashSet;
@@ -20,12 +20,13 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.modules.Modeler.DataModel;
import com.facebook.openwifirrm.ucentral.UCentralConstants;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifi.cloudsdk.UCentralConstants;
import com.facebook.openwifi.cloudsdk.UCentralUtils;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.modules.Modeler.DataModel;
import com.facebook.openwifi.rrm.modules.ModelerUtils;
/**
* Least used channel optimizer.
@@ -89,13 +90,13 @@ public class LeastUsedChannelOptimizer extends ChannelOptimizer {
protected static Map<Integer, Integer> getOccupiedOverlapChannels(
Map<Integer, Integer> occupiedChannels
) {
int maxChannel =
UCentralUtils.UPPER_CHANNEL_LIMIT.get(UCentralConstants.BAND_2G);
int minChannel =
UCentralUtils.LOWER_CHANNEL_LIMIT.get(UCentralConstants.BAND_2G);
final int maxChannel =
UCentralUtils.getUpperChannelLimit(UCentralConstants.BAND_2G);
final int minChannel =
UCentralUtils.getLowerChannelLimit(UCentralConstants.BAND_2G);
Map<Integer, Integer> occupiedOverlapChannels = new TreeMap<>();
for (
int overlapChannel : AVAILABLE_CHANNELS_BAND
int overlapChannel : UCentralUtils.AVAILABLE_CHANNELS_BAND
.get(UCentralConstants.BAND_2G)
) {
int occupancy = 0;
@@ -337,11 +338,13 @@ public class LeastUsedChannelOptimizer extends ChannelOptimizer {
UCentralUtils.getDeviceAvailableChannels(
model.latestDeviceStatusRadios,
model.latestDeviceCapabilities,
AVAILABLE_CHANNELS_BAND
UCentralUtils.AVAILABLE_CHANNELS_BAND
);
Map<String, State> latestState =
ModelerUtils.getLatestState(model.latestStates);
Map<String, String> bssidsMap =
UCentralUtils.getBssidsMap(model.latestState);
UCentralUtils.getBssidsMap(latestState);
for (String band : bandsMap.keySet()) {
// Performance metrics
@@ -369,11 +372,12 @@ public class LeastUsedChannelOptimizer extends ChannelOptimizer {
availableChannelsList == null ||
availableChannelsList.isEmpty()
) {
availableChannelsList = AVAILABLE_CHANNELS_BAND.get(band);
availableChannelsList =
UCentralUtils.AVAILABLE_CHANNELS_BAND.get(band);
}
// Get current channel of the device
State state = model.latestState.get(serialNumber);
State state = latestState.get(serialNumber);
if (state == null) {
logger.debug(
"Device {}: No state found, skipping...",
@@ -389,7 +393,12 @@ public class LeastUsedChannelOptimizer extends ChannelOptimizer {
continue;
}
int[] currentChannelInfo =
getCurrentChannel(band, serialNumber, state);
getCurrentChannel(
band,
serialNumber,
state,
model.latestDeviceCapabilities
);
int currentChannel = currentChannelInfo[0];
// Filter out APs if the radios in the state do not contain a
// channel in a band given by the state. This can happen when

View File

@@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.openwifirrm.optimizers.channel;
package com.facebook.openwifi.rrm.optimizers.channel;
import java.util.ArrayList;
import java.util.List;
@@ -19,11 +19,12 @@ import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.facebook.openwifirrm.DeviceDataManager;
import com.facebook.openwifirrm.modules.Modeler.DataModel;
import com.facebook.openwifirrm.ucentral.UCentralUtils;
import com.facebook.openwifirrm.ucentral.WifiScanEntry;
import com.facebook.openwifirrm.ucentral.models.State;
import com.facebook.openwifi.cloudsdk.UCentralUtils;
import com.facebook.openwifi.cloudsdk.WifiScanEntry;
import com.facebook.openwifi.cloudsdk.models.ap.State;
import com.facebook.openwifi.rrm.DeviceDataManager;
import com.facebook.openwifi.rrm.modules.Modeler.DataModel;
import com.facebook.openwifi.rrm.modules.ModelerUtils;
/**
* Random channel initializer.
@@ -125,11 +126,13 @@ public class RandomChannelInitializer extends ChannelOptimizer {
UCentralUtils.getDeviceAvailableChannels(
model.latestDeviceStatusRadios,
model.latestDeviceCapabilities,
AVAILABLE_CHANNELS_BAND
UCentralUtils.AVAILABLE_CHANNELS_BAND
);
Map<String, State> latestState =
ModelerUtils.getLatestState(model.latestStates);
Map<String, String> bssidsMap =
UCentralUtils.getBssidsMap(model.latestState);
UCentralUtils.getBssidsMap(latestState);
for (Map.Entry<String, List<String>> entry : bandsMap.entrySet()) {
// Performance metrics
@@ -149,7 +152,7 @@ public class RandomChannelInitializer extends ChannelOptimizer {
// to get the valid result for single channel assignment
// If the intersection is empty, then turn back to the default channels list
List<Integer> availableChannelsList = new ArrayList<>(
AVAILABLE_CHANNELS_BAND.get(band)
UCentralUtils.AVAILABLE_CHANNELS_BAND.get(band)
);
for (String serialNumber : entry.getValue()) {
List<Integer> deviceChannelsList = deviceAvailableChannels
@@ -158,14 +161,16 @@ public class RandomChannelInitializer extends ChannelOptimizer {
if (
deviceChannelsList == null || deviceChannelsList.isEmpty()
) {
deviceChannelsList = AVAILABLE_CHANNELS_BAND.get(band);
deviceChannelsList =
UCentralUtils.AVAILABLE_CHANNELS_BAND.get(band);
}
availableChannelsList.retainAll(deviceChannelsList);
}
if (
availableChannelsList == null || availableChannelsList.isEmpty()
) {
availableChannelsList = AVAILABLE_CHANNELS_BAND.get(band);
availableChannelsList =
UCentralUtils.AVAILABLE_CHANNELS_BAND.get(band);
logger.debug(
"The intersection of the device channels lists is empty!!! " +
"Fall back to the default channels list"
@@ -183,7 +188,7 @@ public class RandomChannelInitializer extends ChannelOptimizer {
? rng.nextInt(availableChannelsList.size()) : defaultChannelIndex
);
State state = model.latestState.get(serialNumber);
State state = latestState.get(serialNumber);
if (state == null) {
logger.debug(
"Device {}: No state found, skipping...",
@@ -199,7 +204,12 @@ public class RandomChannelInitializer extends ChannelOptimizer {
continue;
}
int[] currentChannelInfo =
getCurrentChannel(band, serialNumber, state);
getCurrentChannel(
band,
serialNumber,
state,
model.latestDeviceCapabilities
);
int currentChannel = currentChannelInfo[0];
int currentChannelWidth = currentChannelInfo[1];
if (currentChannel == 0) {

Some files were not shown because too many files have changed in this diff Show More