forked from KNEMC/KLALB
Compare commits
33
Commits
cc811eddfe
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
189b14a743 | ||
|
|
3b73e2b613 | ||
|
|
ec51e5a778 | ||
|
|
c0e73bce55 | ||
|
|
b898e4c5be | ||
|
|
61bc066f82 | ||
|
|
7f46c1b8c9 | ||
|
|
156d74bbe3 | ||
|
|
862b860020 | ||
|
|
100fad7d18 | ||
|
|
6d6a199728 | ||
|
|
21b975676d | ||
|
|
2c111770b3 | ||
|
|
52f44335e4
|
||
|
|
a06e1cb5eb | ||
|
|
58913254e0 | ||
|
|
02d7bcd93b | ||
|
|
1e52e82d6d | ||
|
|
3023fe5b2a | ||
|
|
7896ee6638
|
||
|
|
ed94423855
|
||
|
|
c3172a04b1
|
||
|
|
cc803f47a7 | ||
|
|
3bb95988fc | ||
|
|
e87e3bb953 | ||
|
|
41db17f1ec | ||
|
|
61868fe93e
|
||
|
|
9cea5ed493
|
||
|
|
e0296e0ccd
|
||
|
|
9cea74943c
|
||
|
|
35c430114e
|
||
|
|
6c7017bc75
|
||
|
|
041cc31c5f
|
+3
-18
@@ -2,32 +2,17 @@
|
|||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="lib" path="lib/gson-2.1.jar"/>
|
<classpathentry kind="lib" path="lib/gson-2.1.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/javassist.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1686963856070/source/javassist-3.29.2-GA-sources.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/ini4j.jar"/>
|
<classpathentry kind="lib" path="lib/ini4j.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/JFreeChart1.5.2.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/toml4j-0.7.1.jar"/>
|
<classpathentry kind="lib" path="lib/toml4j-0.7.1.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/pcap4j-core-1.8.2.jar" sourcepath="C:/Users/ADMINI~1/AppData/Local/Temp/1/.org.sf.feeling.decompiler1725520274095/source/pcap4j-core-1.8.2-sources.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/pcap4j-packetfactory-static-1.8.2.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/pcap4j-sample-1.8.2.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-javadoc.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-sources.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/slf4j-api-2.0.9-tests.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0.jar" sourcepath="lib/disruptor-4.0.0-sources.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-javadoc.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/disruptor-4.0.0-sources.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/KNElib1.0.jar"/>
|
<classpathentry kind="lib" path="lib/KNElib1.0.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/KNEOptimize.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/JavaTUN0.3.jar"/>
|
<classpathentry kind="lib" path="lib/JavaTUN0.3.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/uuid-creator-6.1.1.jar"/>
|
<classpathentry kind="lib" path="lib/KNEOptimize.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6-javadoc.jar"/>
|
|
||||||
<classpathentry kind="lib" path="lib/jctools-core-4.0.6-sources.jar"/>
|
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="module" value="true"/>
|
<attribute name="module" value="true"/>
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
|
<classpathentry kind="lib" path="lib/jfreechart-1.5.3.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/jfreechart-1.5.3-sources.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
+13
@@ -3,3 +3,16 @@
|
|||||||
/klalbs4.json
|
/klalbs4.json
|
||||||
/klalbs.json
|
/klalbs.json
|
||||||
/klalbs2.json
|
/klalbs2.json
|
||||||
|
|
||||||
|
# Dashboard / Frontend
|
||||||
|
dashboard/node_modules/
|
||||||
|
dashboard/dist/
|
||||||
|
dashboard/.pnpm-store/
|
||||||
|
.pnpm-debug.log*
|
||||||
|
dashboard/.env.local
|
||||||
|
dashboard/.env.*.local
|
||||||
|
|
||||||
|
/klalb-config.json
|
||||||
|
/klalbconfig-old.json
|
||||||
|
|
||||||
|
/.slim/
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "dashboard"]
|
||||||
|
path = dashboard
|
||||||
|
url = https://git.code.cq.cn/SerinaNya/KLALB-dashboard.git
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="jctools-core-jdk11-4.0.7">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jctools-core-jdk11-4.0.7.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jctools-core-jdk11-4.0.7-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
||||||
Generated
+38
@@ -0,0 +1,38 @@
|
|||||||
|
<component name="libraryTable">
|
||||||
|
<library name="jfreechart-1.5.3">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jfreechart-1.5.3.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/disruptor-4.0.0.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/gson-2.1.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/ini4j.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/javassist.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/JavaTUN0.3.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jctools-core-4.0.6.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/KNElib1.0.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/KNEOptimize.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/pcap4j-core-1.8.2.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/pcap4j-packetfactory-propertiesbased-1.8.2.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/pcap4j-packetfactory-static-1.8.2.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/pcap4j-packettest-1.8.2-tests.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/pcap4j-sample-1.8.2.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/slf4j-api-2.0.9.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/slf4j-api-2.0.9-tests.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/toml4j-0.7.1.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/uuid-creator-6.1.1.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jctools-core-4.0.6-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jfreechart-1.5.3-sources.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/disruptor-4.0.0-sources.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/ini4j.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/JavaTUN0.3.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/jctools-core-4.0.6-sources.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/KNElib1.0.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/slf4j-api-2.0.9-sources.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/toml4j-0.7.1.jar!/" />
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/uuid-creator-6.1.1-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
</component>
|
||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_26" project-jdk-name="jdk-26.0.1" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/classes" />
|
<output url="file://$PROJECT_DIR$/classes" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+1
@@ -2,5 +2,6 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/dashboard" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -6,12 +6,14 @@ KLALB ("KLALB Decentralized SRv6 Network") — Java load-balancing/tunnel system
|
|||||||
|
|
||||||
No Maven/Gradle. Plain Eclipse/IntelliJ project: dependencies are vendored jars in `lib/`, output goes to `bin/` (gitignored). When adding a jar, update **both** `.classpath` and `KLALB.iml`.
|
No Maven/Gradle. Plain Eclipse/IntelliJ project: dependencies are vendored jars in `lib/`, output goes to `bin/` (gitignored). When adding a jar, update **both** `.classpath` and `KLALB.iml`.
|
||||||
|
|
||||||
Compile (verified; `-encoding UTF-8` is mandatory — sources contain Chinese text):
|
Compile (`javac` is NOT on PATH — use the full JDK path; `-encoding UTF-8` is mandatory because sources contain Chinese text):
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
& javac -encoding UTF-8 -cp "lib/*" -d bin (Get-ChildItem -Recurse src -Filter *.java | ForEach-Object FullName)
|
& "C:\Program Files\Zulu\zulu-25\bin\javac.exe" -encoding UTF-8 -cp "lib/*" -d bin (Get-ChildItem -Recurse src -Filter *.java | ForEach-Object FullName)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Warnings about `ThreadTool` varargs / deprecated `finalize` are pre-existing and expected — success = exit code 0. After recompiling, restart the running app (IDE-debugged JVMs keep old classes).
|
||||||
|
|
||||||
Run from the repo root — CWD matters:
|
Run from the repo root — CWD matters:
|
||||||
- reads `klalb-config.json` from CWD
|
- reads `klalb-config.json` from CWD
|
||||||
- loads native libs from CWD: `tuntap4j.dll/.so/.dylib`, `wintun.dll`, `fastcopy.dll` (TUN device support)
|
- loads native libs from CWD: `tuntap4j.dll/.so/.dylib`, `wintun.dll`, `fastcopy.dll` (TUN device support)
|
||||||
@@ -26,8 +28,8 @@ IDE metadata targets JDK 26 (`jdk-26.0.1`); the tree also compiles cleanly on JD
|
|||||||
Runtime gotchas (all verified):
|
Runtime gotchas (all verified):
|
||||||
- On JDK 25, `KNEOptimize.jar`'s `FastLib` reflects into `jdk.internal.misc.Unsafe`; without the two JVM flags above it throws `InaccessibleObjectException` at startup (app still runs).
|
- On JDK 25, `KNEOptimize.jar`'s `FastLib` reflects into `jdk.internal.misc.Unsafe`; without the two JVM flags above it throws `InaccessibleObjectException` at startup (app still runs).
|
||||||
- Creating the SRv6 TUN adapter (`WintunCreateAdapter`) requires an elevated shell; without admin rights it logs "创建虚拟网卡失败" and continues with only the `inLoopBack` interface — links/bridges still work.
|
- Creating the SRv6 TUN adapter (`WintunCreateAdapter`) requires an elevated shell; without admin rights it logs "创建虚拟网卡失败" and continues with only the `inLoopBack` interface — links/bridges still work.
|
||||||
- To disable TUN creation completely (e.g. for non-admin UI/routing testing), set `"TUNName": null` in `klalb-config.json` or leave the TUN Name empty in GUI settings. If omitted, it defaults to `"KLALB_SRv6"`.
|
- To disable TUN creation completely (e.g. for non-admin UI/routing testing), set `"enableTUN": false` in `klalb-config.json` or toggle off "启用 TUN 虚拟网卡" in GUI/Web settings.
|
||||||
- Routing broadcast (`RouterInfo`) transmits `deviceName` across the network, which topology and node overview panels display. `deviceDescription` and `ExtraRoutes` remain local controller configs.
|
- Routing broadcast (`RouterInfo`) transmits `deviceName`, which topology and node overview panels display. `deviceDescription` is NOT broadcast — it only leaves the node in full node-info query responses (see srv6 API below); `ExtraRoutes` remain local controller configs.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
@@ -35,19 +37,63 @@ No test suite, no CI. Classes named `*Test*` (`nathole/`, `ntp/`) are manual `ma
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- Entrypoint `org.kne.cloud.network.klalb.KLALBMain`: load config → build `KLALBProxySystem` → open Swing GUI (`KLALBStateGUI3`) unless `"nogui": true` → interactive console (`help`, `links-state`, `route`, `kperf`, ...).
|
- Entrypoint `org.kne.cloud.network.klalb.KLALBMain`: load config → build `KLALBProxySystem` → open Swing GUI (`KLALBStateGUI3`) unless `"nogui": true` → start `KLALBWebServer` (if `"webUI": true` or web server enabled, default port `4665`) → interactive console (`help`, `links-state`, `route`, `kperf`, ...).
|
||||||
|
- `org.kne.cloud.network.klalb.web.KLALBWebServer` — built-in HTTP/SSE server (JDK `HttpServer`):
|
||||||
|
- API endpoints: `/api/status`, `/api/events` (SSE stream, 200ms intervals), `/api/links`, `/api/links/action`, `/api/links/reconnect`, `/api/routing-table`, `/api/nodes` (topology graph), `/api/node-info?address=<ipv6>` (on-demand full node info), `/api/config`.
|
||||||
|
- Static file hosting / SPA fallback: serves `dashboard/dist/` assets directly.
|
||||||
- `org.kne.cloud.network` — generic socket framework: `VirtualSocket*` hierarchy, `SocketBridge` port-forwarding proxies, `ProtocolDetector` (multi-protocol mux on one port), `MultiProtocolSocketAddress` = URI-style addresses (`tcp://`, `udp://`, `kltp://`, `ntp://`) dispatched through the `SocketType` registry.
|
- `org.kne.cloud.network` — generic socket framework: `VirtualSocket*` hierarchy, `SocketBridge` port-forwarding proxies, `ProtocolDetector` (multi-protocol mux on one port), `MultiProtocolSocketAddress` = URI-style addresses (`tcp://`, `udp://`, `kltp://`, `ntp://`) dispatched through the `SocketType` registry.
|
||||||
- `...network.klalb` — app core: `KLALBController` (the virtual SRv6 network), `KLALBRemoteLink` (WAN lines), `*Packet` wire-format classes, virtual socket implementations.
|
- `...network.klalb` — app core: `KLALBController` (the virtual SRv6 network), `KLALBRemoteLink` (WAN lines), `*Packet` wire-format classes, virtual socket implementations.
|
||||||
- `...network.congestion` — pluggable congestion control (BBR, Vegas2, DCTCP...), chosen via `"congestionAlgorithm"` in config.
|
- `...network.congestion` — pluggable congestion control (BBR, Vegas2, DCTCP...), chosen via `"congestionAlgorithm"` in config.
|
||||||
- `...network.kltp` — custom reliable transport protocol (packets/streams).
|
- `...network.kltp` — custom reliable transport protocol (packets/streams).
|
||||||
- `...network.ipv6`, `...network.srv6` — packet codecs, route table, Dijkstra path computation.
|
- `...network.ipv6`, `...network.srv6` — packet codecs, route table, Dijkstra path computation.
|
||||||
|
- **Node-info query API** (`...network.srv6`, JSON datagrams on `KLALBRoutingProtocol.DEFAULT_PORT=1001`): `KLALBRoutingProtocolAPIServer/Client` speak two request types —
|
||||||
|
- `nodeinfotinyreq/resp` → device name ONLY; never gated by any flag (name is public via broadcast anyway).
|
||||||
|
- `nodeinfofullreq/resp` → externalEndpoints + deviceName + deviceDescription. `denyExternalEndpointQuery=true` hides ONLY the endpoint list (`data=null`); name/description still answer.
|
||||||
|
- GUI rule: opening `NodeInformationPanel` = Full query; use `requestNodeInfoTiny` for lightweight/background lookups. Legacy `openlines*` message types were removed — mixed-version meshes get silence, so upgrade the whole network together.
|
||||||
|
- `JsonDataPacket` stores its UTF-8 payload length in a 2-byte header field: keep every JSON message under 64 KiB.
|
||||||
- `...network.frpc` — frp client integration.
|
- `...network.frpc` — frp client integration.
|
||||||
- `...klalb.ui` — all Swing UI code.
|
- `...klalb.ui` — all Swing UI code.
|
||||||
|
|
||||||
|
## Frontend (Dashboard)
|
||||||
|
|
||||||
|
Located in `dashboard/`:
|
||||||
|
- **Git layout**: `dashboard/` is a separate git repo wired in as a submodule (own origin on `git.code.cq.cn`). Commit frontend changes inside `dashboard/` first, then bump the submodule pointer in the parent repo — parent-repo commits alone do not capture them.
|
||||||
|
- **Stack**: Vite + React 19 + TypeScript + Tailwind CSS v4 + `@base-ui/react` (style: `base-nova`, icons: `lucide-react`, toasts: `@base-ui/react/toast`).
|
||||||
|
- **Routing**: Hash-based routing (`#/overview`, `#/connections`, `#/routing-table`, `#/topology`, `#/settings`) for seamless SPA hosting under Java `KLALBWebServer`.
|
||||||
|
- **Package Manager**: `pnpm` (run all commands from `dashboard/` directory).
|
||||||
|
- **Component installation**: **Must** use CLI via `pnpm dlx shadcn@latest add <component>` (e.g. `pnpm dlx shadcn@latest add alert card badge toast`). Never create or fake shadcn components manually. Non-shadcn libs (`@xyflow/react`, `d3-force`) are installed via plain `pnpm add`.
|
||||||
|
- **Commands**:
|
||||||
|
- `pnpm dev` — Start Vite dev server (proxies `/api` to backend `http://127.0.0.1:4665`).
|
||||||
|
- `pnpm build` — Typecheck and build SPA to `dashboard/dist` (which Java `KLALBWebServer` serves directly).
|
||||||
|
- `pnpm lint` / `pnpm typecheck` — Verification.
|
||||||
|
- **Pages & data flow**:
|
||||||
|
- Overview / Connections read the SSE stream (`use-klalb-sse.ts`, 200ms pushes of status + links).
|
||||||
|
- Settings loads/saves `/api/config` (`use-klalb-config.ts`); save payload must keep legacy field aliases alongside new names for compatibility.
|
||||||
|
- Routing table polls `/api/routing-table` every 1s (`use-routing-table.ts`); `cost` is delay-derived and displayed in milliseconds.
|
||||||
|
- Topology polls `/api/nodes` every 1s (`use-topology.ts`) — SSE does NOT carry topology.
|
||||||
|
- Selecting a topology node queries `/api/node-info`; remote node descriptions require a full SRv6 node-info request and can time out after 3s.
|
||||||
|
- Topology layout: `d3-force` headless simulation (recomputed only when node/edge structure changes) rendered by `@xyflow/react` with custom `device-node` / `link-edge` components in `src/components/topology/`.
|
||||||
|
- React hooks lint rule forbids `setState` synchronously inside effects — initialize form state via component `key` remount + lazy `useState(() => ...)` initializers (see `SettingsForm` pattern).
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|
||||||
`klalb-config.json` is an array of items discriminated by their `"Type"` field. Adding a new item type requires a `KLALBConfigItem` subclass **plus** new cases in both `KLALBConfigItem.getDefaultJsonDeserializer()` and `getDefaultJsonSerializer()`; unknown types are preserved as `UnknownKLALBConfigItem`. Any Gson instance handling config must register these adapters via `registerToGsonBuilder` (see `KLALBProxySystem`).
|
`klalb-config.json` is an array of items discriminated by their `"Type"` field. Adding a new item type requires a `KLALBConfigItem` subclass **plus** new cases in both `KLALBConfigItem.getDefaultJsonDeserializer()` and `getDefaultJsonSerializer()`; unknown types are preserved as `UnknownKLALBConfigItem`. Any Gson instance handling config must register these adapters via `registerToGsonBuilder` (see `KLALBProxySystem`).
|
||||||
|
|
||||||
|
Key controller config fields:
|
||||||
|
- `externalEndpoints` / `autoConnections`: published vs auto-connect endpoint lists (renamed from `openConnections`, which itself replaced legacy `LineTable`; the old name was a developer naming mistake — these addresses are this node's externally published endpoints, not "connections").
|
||||||
|
- `ntpServers`: time server list (replaces `ntpServerTable`).
|
||||||
|
- `denyExternalEndpointQuery` / `denyExternalEndpointBroadcast`: safety flags — the query flag hides ONLY the external-endpoint list in full node-info responses (device name/description still answer; Tiny queries are never gated), the broadcast flag disables LAN multicast discovery (renamed from `denyConnectionQuery` / `denyConnectionBroadcast`, which replaced `denyLineTableQuery` / `denyLineTableBroadcast`).
|
||||||
|
- `enableTUN`: boolean flag for TUN interface creation (`"TUNName"` configures device name).
|
||||||
|
- `webListen`: Web API listen address, normally `http://0.0.0.0:4665`; legacy `webPort` is accepted on load/API input.
|
||||||
|
|
||||||
|
Legacy JSON keys are still accepted on load: `KLALBConfigItem.getDefaultJsonDeserializer()` normalizes old key names (`openConnections`/`LineTable`, `denyConnectionQuery`, `denyLineTable*`, ...) before reflective deserialization (manual rewrite because gson-2.1 has no `@SerializedName(alternate=...)`), and `handleConfig` in the web server accepts them too. New saves always write canonical names.
|
||||||
|
|
||||||
|
Gson quirks:
|
||||||
|
- **gson-2.1 (vendored) is ancient**: its `JSON_ELEMENT` adapter factory only matches exact `JsonElement.class`, NOT subclasses. Calling `gson.toJson(Object)` with a runtime `JsonObject`/`JsonArray` reflectively serializes the internal field as `{"members": {...}}`. `KLALBWebServer.sendJsonResponse` guards against this by using `JsonElement.toString()` for JsonElement instances — keep that guard when adding new response paths. SSE avoids the issue entirely via `JsonObject.toString()`.
|
||||||
|
- `/api/config` GET/POST is parsed field-by-field in `KLALBWebServer.handleConfig` (NOT whole-object Gson reflection) because polymorphic fields (`List<InetAddress>`, `List<MultiProtocolSocketAddress>`) break reflective mapping. Keep new config fields in sync there, accepting both legacy and new JSON key names.
|
||||||
|
- `InetAddress`, `MultiProtocolSocketAddress`, and `KLALBConfigItem` custom adapters are registered on the shared Gson in `KLALBProxySystem`; the web server reuses that instance via `proxySystem.getGson()`.
|
||||||
|
- Saving via web API persists through `KLALBProxySystem.saveConfigToFile()` (GUI save consumer takes precedence when present).
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
- Sources are UTF-8; comments, log/UI strings, and commit messages are largely Chinese.
|
- Sources are UTF-8; comments, log/UI strings, and commit messages are largely Chinese.
|
||||||
|
|||||||
@@ -249,5 +249,7 @@
|
|||||||
</library>
|
</library>
|
||||||
</orderEntry>
|
</orderEntry>
|
||||||
<orderEntry type="jdk" jdkName="jdk-26.0.1" jdkType="JavaSDK" />
|
<orderEntry type="jdk" jdkName="jdk-26.0.1" jdkType="JavaSDK" />
|
||||||
|
<orderEntry type="library" name="jfreechart-1.5.3" level="project" />
|
||||||
|
<orderEntry type="library" name="jctools-core-jdk11-4.0.7" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
Binary file not shown.
-20
@@ -1,20 +0,0 @@
|
|||||||
//加速线路
|
|
||||||
{KLALBRemote}->43.248.189.107:35000
|
|
||||||
{KLALBRemote}->cn-bj-bgp-3.openfrp.top:65529
|
|
||||||
{KLALBRemote}->180.76.147.250:65529
|
|
||||||
{KLALBRemote}->cn-ah-dx-1.natfrp.cloud:65529
|
|
||||||
{KLALBRemote}->cn-nn-dx-1.natfrp.cloud:65529
|
|
||||||
{KLALBRemote}->cn-wh-dx-1.natfrp.cloud:65529
|
|
||||||
{KLALBRemote}->cn-zz-bgp-10.natfrp.cloud:23330
|
|
||||||
{KLALBRemote}->cn-zz-bgp-7.natfrp.cloud:33336
|
|
||||||
{KLALBRemote}->43.143.109.64:49965
|
|
||||||
{KLALBRemote}->frp.104300.xyz:49965
|
|
||||||
{KLALBRemote}->us.afrps.cn:49966
|
|
||||||
{KLALBRemote}->hk.afrps.cn:49966
|
|
||||||
{KLALBRemote}->la.afrps.cn:49966
|
|
||||||
{KLALBRemote}->frp.freefrp.net:49965
|
|
||||||
{KLALBRemote}->frp1.freefrp.net:49965
|
|
||||||
{KLALBRemote}->frp2.freefrp.net:49965
|
|
||||||
{KLALBRemote}->frp4.freefrp.net:49965
|
|
||||||
|
|
||||||
0.0.0.0:25565->{KLALBVirtual}[171d:a999:e697:4b23:ae52:9f29:4532:e1ee]:25565
|
|
||||||
Submodule
+1
Submodule dashboard added at 885a0c2d89
Binary file not shown.
@@ -1,107 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"language": "ZH_CN",
|
|
||||||
"nogui": false,
|
|
||||||
"VirtualAddress": "2486:1:0:0:0:0:0:8889",
|
|
||||||
"VirtualASN": 2142606939373348329,
|
|
||||||
"DNS": [
|
|
||||||
"2486:1:0:0:0:0:0:8888"
|
|
||||||
],
|
|
||||||
"TCPListen": "tcp://0.0.0.0:4565",
|
|
||||||
"UDPListen": "udp://0.0.0.0:4572",
|
|
||||||
"VirtualSocketName": "kltp",
|
|
||||||
"LineTable": [
|
|
||||||
"tcp://kne03.yoyo250.fun:4565",
|
|
||||||
"tcp://kne04.yoyo250.fun:4565"
|
|
||||||
],
|
|
||||||
"ConnectLineTable": [
|
|
||||||
"tcp://07f4acdef99b.ofalias.net:4565",
|
|
||||||
"tcp://kne01.yoyo250.fun:4565",
|
|
||||||
"tcp://kne02.yoyo250.fun:4565"
|
|
||||||
],
|
|
||||||
"ntpServerTable": [
|
|
||||||
"ntp://ntp1.aliyun.com",
|
|
||||||
"ntp://ntp2.aliyun.com",
|
|
||||||
"ntp://ntp3.aliyun.com",
|
|
||||||
"ntp://ntp4.aliyun.com",
|
|
||||||
"ntp://ntp5.aliyun.com",
|
|
||||||
"ntp://ntp6.aliyun.com",
|
|
||||||
"ntp://ntp7.aliyun.com",
|
|
||||||
"ntp://ntp1.tencent.com",
|
|
||||||
"ntp://ntp2.tencent.com",
|
|
||||||
"ntp://ntp4.tencent.com",
|
|
||||||
"ntp://ntp5.tencent.com",
|
|
||||||
"ntp://time.google.com",
|
|
||||||
"ntp://time.apple.com",
|
|
||||||
"ntp://pool.ntp.org",
|
|
||||||
"ntp://ntp.ntsc.ac.cn",
|
|
||||||
"ntp://us.ntp.org.cn"
|
|
||||||
],
|
|
||||||
"ExtraRoutes": [],
|
|
||||||
"denyLineTableQuery": false,
|
|
||||||
"denyLineTableBroadcast": false,
|
|
||||||
"congestionAlgorithm": "BBR",
|
|
||||||
"burstLimit": 2.0,
|
|
||||||
"delayUpperBound": 1.2,
|
|
||||||
"delayLowerBound": 1.1,
|
|
||||||
"nagleDelayTime": 1000000,
|
|
||||||
"linkNagleDelayTime": 0,
|
|
||||||
"linkConnectionsCount": 1,
|
|
||||||
"TUNName": null,
|
|
||||||
"performanceStrategy": "multiscatter",
|
|
||||||
"DeviceName": "SerinaNya PC",
|
|
||||||
"DeviceDescription": "desc",
|
|
||||||
"NetworkInterfaceExcepts": [],
|
|
||||||
"Type": "KLALBController"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Listen": "kltp://[::0]:5201",
|
|
||||||
"Bridge": {
|
|
||||||
"DEFAULT": "SocketBridge"
|
|
||||||
},
|
|
||||||
"Connect": {
|
|
||||||
"DEFAULT": "tcp://127.0.0.1:5201"
|
|
||||||
},
|
|
||||||
"Type": "SocketBridge"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Listen": "tcp://[::1]:5202",
|
|
||||||
"Bridge": {
|
|
||||||
"DEFAULT": "SocketBridge"
|
|
||||||
},
|
|
||||||
"Connect": {
|
|
||||||
"DEFAULT": "kltp://[2486:5acd:e339:4837:a6d9:3aed:4de2:30fd]:5201"
|
|
||||||
},
|
|
||||||
"Type": "SocketBridge"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Listen": "tcp://127.0.0.1:35000",
|
|
||||||
"Bridge": {
|
|
||||||
"DEFAULT": "SocketBridge"
|
|
||||||
},
|
|
||||||
"Connect": {
|
|
||||||
"DEFAULT": "kltp://[2486:1::8888]:23333"
|
|
||||||
},
|
|
||||||
"Type": "SocketBridge"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Listen": "kltp://[::0]:25565",
|
|
||||||
"Bridge": {
|
|
||||||
"DEFAULT": "SocketBridge"
|
|
||||||
},
|
|
||||||
"Connect": {
|
|
||||||
"DEFAULT": "tcp://127.0.0.1:25566"
|
|
||||||
},
|
|
||||||
"Type": "SocketBridge"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Listen": "tcp://127.0.0.1:35565",
|
|
||||||
"Bridge": {
|
|
||||||
"DEFAULT": "SocketBridge"
|
|
||||||
},
|
|
||||||
"Connect": {
|
|
||||||
"DEFAULT": "kltp://[2486:1::8888]:25565"
|
|
||||||
},
|
|
||||||
"Type": "SocketBridge"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
[
|
|
||||||
{"Type":"KLALBController" ,
|
|
||||||
"TCPListen" : "0.0.0.0:4565",
|
|
||||||
"UDPListen" : "{UDP}0.0.0.0:4572",
|
|
||||||
"VirtualSocketName" : "KLALB_Stream",
|
|
||||||
"LineTable":["43.248.189.107:65529",
|
|
||||||
"cn-bj-bgp-3.openfrp.top:65529",
|
|
||||||
"180.76.147.250:65529",
|
|
||||||
"cn-ah-dx-1.natfrp.cloud:65529",
|
|
||||||
"cn-nn-dx-1.natfrp.cloud:65529",
|
|
||||||
"cn-wh-dx-1.natfrp.cloud:65529",
|
|
||||||
"cn-zz-bgp-10.natfrp.cloud:23330",
|
|
||||||
"cn-zz-bgp-7.natfrp.cloud:33336",
|
|
||||||
"43.143.109.64:49965",
|
|
||||||
"frp.104300.xyz:49965",
|
|
||||||
"us.afrps.cn:49966",
|
|
||||||
"hk.afrps.cn:49966",
|
|
||||||
"la.afrps.cn:49966",
|
|
||||||
"frp.freefrp.net:49965",
|
|
||||||
"frp1.freefrp.net:49965",
|
|
||||||
"frp2.freefrp.net:49965",
|
|
||||||
"frp4.freefrp.net:49965",
|
|
||||||
"cn-he-plc-2.openfrp.top:4572",
|
|
||||||
"{UDP}cn-he-plc-2.openfrp.top:4572",
|
|
||||||
"frp-mom.top:22226",
|
|
||||||
"frp-man.top:36555",
|
|
||||||
"us-sjc-bgp-2.openfrp.top:36555",
|
|
||||||
"us-sjc-bgp-1.openfrp.top:36555",
|
|
||||||
"[240e:340:d856:b700:6d02:6a6a:f9fc:865b]:4572"]
|
|
||||||
},
|
|
||||||
{"Type":"SocketBridge" ,
|
|
||||||
"Listen" : "0.0.0.0:4572",
|
|
||||||
"Bridge":{
|
|
||||||
"KLALB" : "SocketBridge",
|
|
||||||
"RDP":"SocketBridge",
|
|
||||||
"HTTP":"SocketBridge",
|
|
||||||
"HTTPS":"SocketBridge",
|
|
||||||
"DEFAULT":"MinecraftSocketBridge23332"
|
|
||||||
} ,
|
|
||||||
"Connect" : {
|
|
||||||
"KLALB" : "127.0.0.1:4565",
|
|
||||||
"RDP":"127.0.0.1:3389",
|
|
||||||
"HTTP":"127.0.0.1:5212",
|
|
||||||
"HTTPS":"192.168.1.235:443",
|
|
||||||
"DEFAULT":"127.0.0.1:36555"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"Type":"SocketBridge" ,
|
|
||||||
"Listen" : "{KLALB_Stream}[::0]:23332",
|
|
||||||
"Bridge":"MinecraftSocketBridge23332",
|
|
||||||
"Connect" : "127.0.0.1:36555"
|
|
||||||
},
|
|
||||||
{ "Type":"SocketBridge" ,
|
|
||||||
"Listen" : "{KLALB_Stream}[::0]:23333",
|
|
||||||
"Bridge":"SocketBridge",
|
|
||||||
"Connect" : "127.0.0.1:5212"
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{"Type":"SocketBridge" ,
|
|
||||||
"Listen" : "0.0.0.0:25561",
|
|
||||||
"Bridge":{
|
|
||||||
"KLALB" : "SocketBridge",
|
|
||||||
"DEFAULT":"MinecraftSocketBridge23330"
|
|
||||||
} ,
|
|
||||||
"Connect" : {
|
|
||||||
"KLALB" : "127.0.0.1:4565",
|
|
||||||
"DEFAULT":"127.0.0.1:25562"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{"Type":"SocketBridge" ,
|
|
||||||
"Listen" : "{KLALB_Stream}[::0]:23330",
|
|
||||||
"Bridge":"MinecraftSocketBridge23330",
|
|
||||||
"Connect" : "127.0.0.1:25562"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,29 +0,0 @@
|
|||||||
0.0.0.0:35000(RDP)->192.168.1.233:3389
|
|
||||||
0.0.0.0:35000(HTTPS)->192.168.1.233:8444
|
|
||||||
0.0.0.0:35000(HTTP)->192.168.1.233:5212
|
|
||||||
0.0.0.0:35000(SSH)->192.168.1.236:22
|
|
||||||
0.0.0.0:35000(KLALB)->{KLALBRemote}
|
|
||||||
0.0.0.0:35000->127.0.0.1:35001 //Winds服(普通线路)
|
|
||||||
|
|
||||||
{KLALBVirtual}[::0]:25565->127.0.0.1:35001 //Winds服(加速线路)
|
|
||||||
|
|
||||||
//加速线路
|
|
||||||
{KLALBRemote}->43.248.189.107:35000
|
|
||||||
{KLALBRemote}->cn-bj-bgp-3.openfrp.top:65529
|
|
||||||
{KLALBRemote}->180.76.147.250:65529
|
|
||||||
{KLALBRemote}->cn-ah-dx-1.natfrp.cloud:65529
|
|
||||||
{KLALBRemote}->cn-nn-dx-1.natfrp.cloud:65529
|
|
||||||
{KLALBRemote}->cn-wh-dx-1.natfrp.cloud:65529
|
|
||||||
{KLALBRemote}->cn-zz-bgp-10.natfrp.cloud:23330
|
|
||||||
{KLALBRemote}->cn-zz-bgp-7.natfrp.cloud:33336
|
|
||||||
{KLALBRemote}->43.143.109.64:49965
|
|
||||||
{KLALBRemote}->frp.104300.xyz:49965
|
|
||||||
{KLALBRemote}->us.afrps.cn:49966
|
|
||||||
{KLALBRemote}->hk.afrps.cn:49966
|
|
||||||
{KLALBRemote}->la.afrps.cn:49966
|
|
||||||
{KLALBRemote}->frp.freefrp.net:49965
|
|
||||||
{KLALBRemote}->frp1.freefrp.net:49965
|
|
||||||
{KLALBRemote}->frp2.freefrp.net:49965
|
|
||||||
{KLALBRemote}->frp4.freefrp.net:49965
|
|
||||||
|
|
||||||
0.0.0.0:25565->{KLALBVirtual}[171d:a999:e697:4b23:ae52:9f29:4532:e1ee]:25565
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
43.248.189.107:65529
|
|
||||||
cn-bj-bgp-3.openfrp.top:65529
|
|
||||||
180.76.147.250:65529
|
|
||||||
cn-ah-dx-1.natfrp.cloud:65529
|
|
||||||
cn-nn-dx-1.natfrp.cloud:65529
|
|
||||||
cn-wh-dx-1.natfrp.cloud:65529
|
|
||||||
cn-zz-bgp-10.natfrp.cloud:23330
|
|
||||||
cn-zz-bgp-7.natfrp.cloud:33336
|
|
||||||
43.143.109.64:49965
|
|
||||||
frp.104300.xyz:49965
|
|
||||||
us.afrps.cn:49966
|
|
||||||
hk.afrps.cn:49966
|
|
||||||
la.afrps.cn:49966
|
|
||||||
frp.freefrp.net:49965
|
|
||||||
frp1.freefrp.net:49965
|
|
||||||
frp2.freefrp.net:49965
|
|
||||||
frp4.freefrp.net:49965
|
|
||||||
cn-he-plc-2.openfrp.top:4569
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
0.0.0.0:35000(RDP)->192.168.1.233:3389
|
|
||||||
0.0.0.0:35000(HTTPS)->192.168.1.233:8444
|
|
||||||
0.0.0.0:35000(HTTP)->192.168.1.233:5212
|
|
||||||
0.0.0.0:35000(SSH)->192.168.1.236:22
|
|
||||||
0.0.0.0:35000(KLALB)->{KLALBRemote}
|
|
||||||
0.0.0.0:35000->127.0.0.1:35001 //Winds服(普通线路)
|
|
||||||
|
|
||||||
{KLALBVirtual}[::0]:25565->127.0.0.1:35001 //Winds服(加速线路)
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"skills": {
|
||||||
|
"shadcn": {
|
||||||
|
"source": "shadcn/ui",
|
||||||
|
"sourceType": "github",
|
||||||
|
"skillPath": "skills/shadcn/SKILL.md",
|
||||||
|
"computedHash": "c1a68ee06a668aced9ab2b5fbdea5f989864123794eb2e056b339a072dbb7f10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,3 +112,16 @@ performancestrategy=Performance strategy
|
|||||||
singlecore=Single-Core - Cache Affinity First (Best energy/performance ratio, for low-power & cloud)
|
singlecore=Single-Core - Cache Affinity First (Best energy/performance ratio, for low-power & cloud)
|
||||||
multifill=Multi-Core - Fill Cores Sequentially (Recommended for general-purpose physical servers)
|
multifill=Multi-Core - Fill Cores Sequentially (Recommended for general-purpose physical servers)
|
||||||
multiscatter=Multi-Core - Spread Load Evenly (Optimized for multi-socket NUMA architectures)
|
multiscatter=Multi-Core - Spread Load Evenly (Optimized for multi-socket NUMA architectures)
|
||||||
|
webapisettings=Web API settings
|
||||||
|
enablewebapi=Enable Web API
|
||||||
|
weblistenaddr=Web API listen address
|
||||||
|
invaildweblistenaddr=Invalid Web API listen address
|
||||||
|
enabletun=Enable TUN adapter
|
||||||
|
congestionmonitor=Congestion control monitor
|
||||||
|
rttbaseline=RTT baseline
|
||||||
|
rtt=RTT
|
||||||
|
rttmax=RTT max
|
||||||
|
rttmin=RTT min
|
||||||
|
rto=RTO
|
||||||
|
cpuload=CPU load
|
||||||
|
ramusage=RAM usage
|
||||||
@@ -112,3 +112,16 @@ performancestrategy=性能策略
|
|||||||
singlecore=单核-缓存命中率优先(高能耗比,适合低功耗设备、云机)
|
singlecore=单核-缓存命中率优先(高能耗比,适合低功耗设备、云机)
|
||||||
multifill=多核-负载按顺序填充(适合大多数物理服务器、电脑)
|
multifill=多核-负载按顺序填充(适合大多数物理服务器、电脑)
|
||||||
multiscatter=多核-负载均匀打散分配(适合特殊的多路NUMA服务器)
|
multiscatter=多核-负载均匀打散分配(适合特殊的多路NUMA服务器)
|
||||||
|
webapisettings=Web API 设置
|
||||||
|
enablewebapi=启用 Web API
|
||||||
|
weblistenaddr=Web API 监听地址:端口
|
||||||
|
invaildweblistenaddr=无效的 Web API 监听地址:端口
|
||||||
|
enabletun=启用TUN虚拟网卡
|
||||||
|
congestionmonitor=拥塞控制监视器
|
||||||
|
rttbaseline=往返延迟基线
|
||||||
|
rtt=往返延迟
|
||||||
|
rttmax=往返延迟上限
|
||||||
|
rttmin=往返延迟下限
|
||||||
|
rto=重传超时
|
||||||
|
cpuload=CPU负载
|
||||||
|
ramusage=RAM占用率
|
||||||
@@ -5,6 +5,9 @@ import java.time.LocalDateTime;
|
|||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.kne.math.Long128;
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
@@ -256,4 +259,27 @@ public class NTPTimestamps {
|
|||||||
.setBit(63);
|
.setBit(63);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Long128 median(List<Long128> values) {
|
||||||
|
Objects.requireNonNull(values);
|
||||||
|
if ( values.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("列表不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 创建副本并排序
|
||||||
|
List<Long128> sorted = new ArrayList<>(values);
|
||||||
|
sorted.sort(Long128::compareTo);
|
||||||
|
|
||||||
|
// 2. 计算中位数
|
||||||
|
int size = sorted.size();
|
||||||
|
if (size % 2 == 1) {
|
||||||
|
// 奇数个:取中间值
|
||||||
|
return sorted.get(size / 2);
|
||||||
|
} else {
|
||||||
|
// 偶数个:取中间两个的平均值
|
||||||
|
Long128 left = sorted.get(size / 2 - 1);
|
||||||
|
Long128 right = sorted.get(size / 2);
|
||||||
|
return left.add(right).divide(Long128.valueOf(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
package org.kne.cloud.network;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.net.SocketOption;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.nio.channels.DatagramChannel;
|
||||||
|
import java.nio.channels.MembershipKey;
|
||||||
|
import java.nio.channels.SelectableChannel;
|
||||||
|
import java.nio.channels.SelectionKey;
|
||||||
|
import java.nio.channels.Selector;
|
||||||
|
import java.nio.channels.spi.SelectorProvider;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自制的 UDP AIO 通道,内部使用线程池模拟异步收包。
|
||||||
|
* 用户只需设置回调,无需自己管理线程。
|
||||||
|
*
|
||||||
|
* 完整委托了 DatagramChannel 的所有公共方法。
|
||||||
|
*/
|
||||||
|
public class AsynchronousDatagramChannel implements AutoCloseable {
|
||||||
|
|
||||||
|
private final DatagramChannel delegate;
|
||||||
|
private final ExecutorService workerPool;
|
||||||
|
private final AtomicBoolean running = new AtomicBoolean(true);
|
||||||
|
private volatile ReceiveHandler handler;
|
||||||
|
private final int bufferSize;
|
||||||
|
private int threadCount;
|
||||||
|
|
||||||
|
// ==================== 回调接口 ====================
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ReceiveHandler {
|
||||||
|
void onReceive(SocketAddress from, ByteBuffer data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 构造方法 ====================
|
||||||
|
|
||||||
|
public AsynchronousDatagramChannel() throws IOException {
|
||||||
|
this(65535, Runtime.getRuntime().availableProcessors());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsynchronousDatagramChannel(int bufferSize, int threadCount) throws IOException {
|
||||||
|
this.bufferSize = bufferSize;
|
||||||
|
this.delegate = DatagramChannel.open();
|
||||||
|
delegate.configureBlocking(true);
|
||||||
|
this.threadCount=threadCount;
|
||||||
|
this.workerPool = Executors.newFixedThreadPool(threadCount, r -> {
|
||||||
|
Thread t = new Thread(r, "AsyncDatagramReader");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startWorkers() {
|
||||||
|
|
||||||
|
for (int i = 0; i < threadCount; i++) {
|
||||||
|
workerPool.submit(this::readerLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 核心方法 ====================
|
||||||
|
|
||||||
|
public void setReceiveHandler(ReceiveHandler handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readerLoop() {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize);
|
||||||
|
while (running.get()) {
|
||||||
|
try {
|
||||||
|
buffer.clear();
|
||||||
|
SocketAddress from = delegate.receive(buffer);
|
||||||
|
if (from == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer.flip();
|
||||||
|
ReceiveHandler localHandler = handler;
|
||||||
|
if (localHandler != null) {
|
||||||
|
localHandler.onReceive(from, buffer);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (running.get()) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int send(ByteBuffer data, SocketAddress target) throws IOException {
|
||||||
|
return delegate.send(data, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== DatagramChannel 委托方法 ====================
|
||||||
|
|
||||||
|
// --- 连接相关 ---
|
||||||
|
|
||||||
|
public DatagramChannel connect(SocketAddress remote) throws IOException {
|
||||||
|
return delegate.connect(remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramChannel disconnect() throws IOException {
|
||||||
|
return delegate.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return delegate.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 绑定相关 ---
|
||||||
|
|
||||||
|
public DatagramChannel bind(SocketAddress local) throws IOException {
|
||||||
|
return delegate.bind(local);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketAddress getLocalAddress() throws IOException {
|
||||||
|
return delegate.getLocalAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketAddress getRemoteAddress() throws IOException {
|
||||||
|
return delegate.getRemoteAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 读写相关 ---
|
||||||
|
|
||||||
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
|
return delegate.read(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long read(ByteBuffer[] dsts) throws IOException {
|
||||||
|
return delegate.read(dsts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
|
||||||
|
return delegate.read(dsts, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int write(ByteBuffer src) throws IOException {
|
||||||
|
return delegate.write(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long write(ByteBuffer[] srcs) throws IOException {
|
||||||
|
return delegate.write(srcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
||||||
|
return delegate.write(srcs, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 接收相关 ---
|
||||||
|
|
||||||
|
public SocketAddress receive(ByteBuffer dst) throws IOException {
|
||||||
|
return delegate.receive(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 多播 (Multicast) ---
|
||||||
|
|
||||||
|
public MembershipKey join(InetAddress group, NetworkInterface interf) throws IOException {
|
||||||
|
return delegate.join(group, interf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source) throws IOException {
|
||||||
|
return delegate.join(group, interf, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 选项相关 ---
|
||||||
|
|
||||||
|
public <T> DatagramChannel setOption(SocketOption<T> name, T value) throws IOException {
|
||||||
|
return delegate.setOption(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getOption(SocketOption<T> name) throws IOException {
|
||||||
|
return delegate.getOption(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<SocketOption<?>> supportedOptions() {
|
||||||
|
return delegate.supportedOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 阻塞模式 ---
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isBlocking() {
|
||||||
|
return delegate.isBlocking();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 选择器相关 ---
|
||||||
|
|
||||||
|
public SelectableChannel configureBlocking(boolean block) throws IOException {
|
||||||
|
return delegate.configureBlocking(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectorProvider provider() {
|
||||||
|
return delegate.provider();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int validOps() {
|
||||||
|
return delegate.validOps();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectionKey keyFor(Selector sel) {
|
||||||
|
return delegate.keyFor(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectionKey register(Selector sel, int ops) throws ClosedChannelException {
|
||||||
|
return delegate.register(sel, ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException {
|
||||||
|
return delegate.register(sel, ops, att);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 状态查询 ---
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return delegate.isOpen() && running.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatagramSocket socket() {
|
||||||
|
return delegate.socket();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 关闭方法 ====================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
running.set(false);
|
||||||
|
workerPool.shutdownNow();
|
||||||
|
delegate.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 静态工厂方法 ====================
|
||||||
|
|
||||||
|
public static AsynchronousDatagramChannel open() throws IOException {
|
||||||
|
return new AsynchronousDatagramChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsynchronousDatagramChannel open(int bufferSize) throws IOException {
|
||||||
|
return new AsynchronousDatagramChannel(bufferSize, Runtime.getRuntime().availableProcessors());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsynchronousDatagramChannel open(int bufferSize, int threadCount) throws IOException {
|
||||||
|
return new AsynchronousDatagramChannel(bufferSize, threadCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 测试示例 ====================
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
int port = 4567;
|
||||||
|
AsynchronousDatagramChannel channel = AsynchronousDatagramChannel.open();
|
||||||
|
channel.bind(new InetSocketAddress(port));
|
||||||
|
|
||||||
|
channel.setReceiveHandler((from, data) -> {
|
||||||
|
byte[] bytes = new byte[data.remaining()];
|
||||||
|
data.get(bytes);
|
||||||
|
String msg = new String(bytes);
|
||||||
|
System.out.println("Received from " + from + ": " + msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
System.out.println("Echo server running on port " + port);
|
||||||
|
System.out.println("Press Enter to stop...");
|
||||||
|
System.in.read();
|
||||||
|
|
||||||
|
channel.close();
|
||||||
|
System.out.println("Server stopped.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ import java.io.DataOutputStream;
|
|||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -148,21 +150,39 @@ public class IPMulticastDiscovery implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// 1. 接收用的 ThreadLocal 缓冲区
|
||||||
|
private static final ThreadLocal<ByteBuffer> RX_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(2048));
|
||||||
|
// 2. 发送用的 ThreadLocal 缓冲区 (广播包一般很小)
|
||||||
|
private static final ThreadLocal<ByteBuffer> TX_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(2048));
|
||||||
|
|
||||||
private MultiProtocolSocketAddress receive() throws IOException {
|
private MultiProtocolSocketAddress receive() throws IOException {
|
||||||
byte[] b = new byte[65535];
|
ByteBuffer bbf = RX_BUFFER.get();
|
||||||
DatagramPacket dp = new DatagramPacket(b, b.length);
|
bbf.clear(); // 重置 position=0, limit=2048
|
||||||
|
|
||||||
|
// 借用底层数组
|
||||||
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||||
soc.receive(dp);
|
soc.receive(dp);
|
||||||
ByteArrayInputStream bis = new ByteArrayInputStream(b, 0, dp.getLength());
|
|
||||||
DataInputStream dis = new DataInputStream(bis);
|
// 限制可读范围
|
||||||
String val = dis.readUTF();
|
int length = dp.getLength();
|
||||||
long h=dis.readLong();
|
bbf.limit(length);
|
||||||
long l=dis.readLong();
|
|
||||||
UUID uid=new UUID(h, l);
|
// 直接读 UTF 字符串 (不用 DataInputStream)
|
||||||
dis.close();
|
// 读取前两个字节的长度,然后创建 String
|
||||||
|
int strLen = bbf.getShort() & 0xFFFF; // 无符号转 int
|
||||||
|
byte[] strBytes = new byte[strLen]; // 这里为了 String 还是得分配一次,但很小
|
||||||
|
bbf.get(strBytes);
|
||||||
|
String val = new String(strBytes, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// 直接读两个 Long 拼成 UUID
|
||||||
|
long h = bbf.getLong();
|
||||||
|
long l = bbf.getLong();
|
||||||
|
UUID uid = new UUID(h, l); // UUID 对象很小,年轻代瞬间回收,不用池化
|
||||||
|
|
||||||
MultiProtocolSocketAddress mpsa = new MultiProtocolSocketAddress(val);
|
MultiProtocolSocketAddress mpsa = new MultiProtocolSocketAddress(val);
|
||||||
if(mpsa.getInetAddress().isAnyLocalAddress()){
|
|
||||||
mpsa=new MultiProtocolSocketAddress(mpsa.getProtocol(),dp.getAddress().getHostAddress(),mpsa.getPort());
|
if (mpsa.getInetAddress().isAnyLocalAddress()) {
|
||||||
|
mpsa = new MultiProtocolSocketAddress(mpsa.getProtocol(), dp.getAddress().getHostAddress(), mpsa.getPort());
|
||||||
}
|
}
|
||||||
if(debug) {
|
if(debug) {
|
||||||
if(uid.equals(selfUUID)) {
|
if(uid.equals(selfUUID)) {
|
||||||
@@ -176,15 +196,23 @@ public class IPMulticastDiscovery implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void send(MultiProtocolSocketAddress multiProtocolSocketAddress) throws IOException {
|
private void send(MultiProtocolSocketAddress multiProtocolSocketAddress) throws IOException {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteBuffer bbf = TX_BUFFER.get();
|
||||||
DataOutputStream dops = new DataOutputStream(baos);
|
bbf.clear(); // 重置
|
||||||
dops.writeUTF(multiProtocolSocketAddress.toString());
|
|
||||||
dops.writeLong(selfUUID.getMostSignificantBits());
|
// 写字符串 (长度 + 字节)
|
||||||
dops.writeLong(selfUUID.getLeastSignificantBits());
|
byte[] strBytes = multiProtocolSocketAddress.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
dops.close();
|
bbf.putShort((short) strBytes.length);
|
||||||
byte[] b = baos.toByteArray();
|
bbf.put(strBytes);
|
||||||
DatagramPacket dp = new DatagramPacket(b, b.length, group);
|
|
||||||
|
// 写 UUID
|
||||||
|
bbf.putLong(selfUUID.getMostSignificantBits());
|
||||||
|
bbf.putLong(selfUUID.getLeastSignificantBits());
|
||||||
|
|
||||||
|
bbf.flip(); // 准备读取
|
||||||
|
|
||||||
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit(), group);
|
||||||
soc.send(dp);
|
soc.send(dp);
|
||||||
|
|
||||||
if(debug)
|
if(debug)
|
||||||
System.out.println(ninterface.getDisplayName()+" 发送广播:"+ multiProtocolSocketAddress +" "+group+" "+selfUUID);
|
System.out.println(ninterface.getDisplayName()+" 发送广播:"+ multiProtocolSocketAddress +" "+group+" "+selfUUID);
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,13 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
|
|
||||||
private Consumer<Long> windowControlConsumer;
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
|
||||||
private long MIN_RTTVAR = 5000000L;
|
|
||||||
private volatile long RTTMin = 1000000000L;
|
private volatile long RTTMin = 1000000000L;
|
||||||
private volatile long RTTVar = 1000000000L;
|
|
||||||
private volatile long RTTAvg = 1000000000L;
|
|
||||||
private volatile long RTTAvg2 = 1000000000L;
|
private volatile long RTTAvg2 = 1000000000L;
|
||||||
private volatile long RTTTotal = 0;
|
private volatile long RTTTotal = 0;
|
||||||
private volatile long RTTCount = 0;
|
private volatile long RTTCount = 0;
|
||||||
private volatile long RTO = 1000000000L;
|
|
||||||
|
|
||||||
|
private RTTEstimator rttEstimator=new RTTEstimator();
|
||||||
|
|
||||||
|
|
||||||
private volatile long window=MIN_WINDOW;
|
private volatile long window=MIN_WINDOW;
|
||||||
@@ -54,10 +53,7 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
} else {
|
} else {
|
||||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
}
|
}
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
rttEstimator.putRTT(latencyns);
|
||||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
|
||||||
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
|
||||||
|
|
||||||
RTTTotal += latencyns;
|
RTTTotal += latencyns;
|
||||||
RTTCount++;
|
RTTCount++;
|
||||||
@@ -93,13 +89,13 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRTO() {
|
public long getRTO() {
|
||||||
return RTO;
|
return rttEstimator.getRTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,4 +132,29 @@ public class BBRCongestionAlgorithm implements CongestionAlgorithm ,DetnetConges
|
|||||||
return "BBR";
|
return "BBR";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBaseRTT() {
|
||||||
|
return rttEstimator.getBaseRTT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCurrentRTT() {
|
||||||
|
return rttEstimator.getCurrentRTT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getUpperDelayBound() {
|
||||||
|
return MAX_GAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLowerDelayBound() {
|
||||||
|
return MIN_GAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBurstLimit() {
|
||||||
|
return burstLimit;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ public interface CongestionAlgorithm {
|
|||||||
public void reset();
|
public void reset();
|
||||||
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
public void setWindowControlConsumer(Consumer<Long>windowControlConsumer);
|
||||||
public void putAck(long packetSize,long RTTns,boolean ecn);
|
public void putAck(long packetSize,long RTTns,boolean ecn);
|
||||||
default public void putAck(long packetSize,long RTTns,long OWDup,boolean ecn) {
|
public void putLoss(long packetSize,long lossns);
|
||||||
putAck(packetSize,RTTns,ecn);
|
|
||||||
}
|
|
||||||
public void putLoss(long packetSize,long lossns,int losscounter);
|
|
||||||
public void setCurrentWindowUsed(long maxwindow);
|
public void setCurrentWindowUsed(long maxwindow);
|
||||||
public void setCurrentBandwidth(long bandwidth);
|
public void setCurrentBandwidth(long bandwidth);
|
||||||
public long getRTO();
|
public long getRTO();
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
|
public long getBaseRTT();
|
||||||
|
|
||||||
|
public long getCurrentRTT();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
package org.kne.cloud.network.congestion;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.jctools.counters.FixedSizeStripedLongCounter;
|
|
||||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
|
||||||
|
|
||||||
public class DCTCP2CongestionAlgorithm implements CongestionAlgorithm {
|
|
||||||
|
|
||||||
private static final long BURST_TIME = 1000000L;
|
|
||||||
private static final long BIAS = 2000000L;
|
|
||||||
private static long MIN_WINDOW = 8192;
|
|
||||||
|
|
||||||
private Consumer<Long> windowControlConsumer;
|
|
||||||
|
|
||||||
private long MIN_RTTVAR = 100000000L;
|
|
||||||
private volatile long RTTVar = 1000000000L;
|
|
||||||
private volatile long RTTAvg = 1000000000L;
|
|
||||||
private double ECNAvg2 = 0L;
|
|
||||||
private double alpha=0;
|
|
||||||
private volatile FixedSizeStripedLongCounter ECNSize = KLALBUtils.createCounter();
|
|
||||||
private volatile FixedSizeStripedLongCounter TotalSize = KLALBUtils.createCounter();
|
|
||||||
private volatile long RTO = 500000000L;
|
|
||||||
|
|
||||||
|
|
||||||
private volatile long window=MIN_WINDOW;
|
|
||||||
private volatile long maxwindow = 99999999999L;
|
|
||||||
private volatile long congressWindowSize=MIN_WINDOW;
|
|
||||||
|
|
||||||
private long RTTstartTime = System.nanoTime();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset() {
|
|
||||||
window = MIN_WINDOW;
|
|
||||||
if (windowControlConsumer != null) {
|
|
||||||
windowControlConsumer.accept(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
|
|
||||||
this.windowControlConsumer = windowControlConsumer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void putAck(long packetSize, long latencyns, boolean ecn) {
|
|
||||||
|
|
||||||
|
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
|
||||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
|
||||||
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
|
||||||
|
|
||||||
if(ecn) {
|
|
||||||
ECNSize.inc(packetSize);
|
|
||||||
}
|
|
||||||
TotalSize.inc(packetSize);
|
|
||||||
|
|
||||||
|
|
||||||
long curr=System.nanoTime();
|
|
||||||
if(curr-RTTstartTime>(RTTAvg+BIAS)) {
|
|
||||||
RTTstartTime=curr;
|
|
||||||
|
|
||||||
long totalSize=TotalSize.getAndReset();
|
|
||||||
long ecnSize=ECNSize.getAndReset();
|
|
||||||
if(totalSize!=0) {
|
|
||||||
ECNAvg2=ecnSize/(double)totalSize;
|
|
||||||
alpha=(alpha*7+ECNAvg2)/8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ECNAvg2>0.5) {
|
|
||||||
congressWindowSize-=200;
|
|
||||||
}else if(ECNAvg2>0.01){
|
|
||||||
congressWindowSize+=200;
|
|
||||||
}else {
|
|
||||||
congressWindowSize+=4000;
|
|
||||||
}
|
|
||||||
//System.out.println(ECNAvg2);
|
|
||||||
//System.out.println(speed+" "+window);
|
|
||||||
|
|
||||||
updateWindowSize();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateWindowSize() {
|
|
||||||
if(congressWindowSize<MIN_WINDOW) {
|
|
||||||
congressWindowSize=MIN_WINDOW;
|
|
||||||
}else if(congressWindowSize>maxwindow) {
|
|
||||||
congressWindowSize=maxwindow;
|
|
||||||
}
|
|
||||||
window=Math.max( congressWindowSize,MIN_WINDOW);
|
|
||||||
if (windowControlConsumer != null) {
|
|
||||||
windowControlConsumer.accept(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getRTO() {
|
|
||||||
return RTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCurrentWindowUsed(long used) {
|
|
||||||
this.maxwindow=(long) (used*1.5)+MIN_WINDOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCurrentBandwidth(long bandwidth) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "DCTCP2";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -13,16 +13,13 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
|
|
||||||
private Consumer<Long> windowControlConsumer;
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
|
||||||
private AtomicBoolean firstUpdate = new AtomicBoolean(true);
|
|
||||||
private long MIN_RTTVAR = 100000000L;
|
|
||||||
private volatile long RTTMin = 1000000000L;
|
private volatile long RTTMin = 1000000000L;
|
||||||
private volatile long RTTVar = 1000000000L;
|
|
||||||
private volatile long RTTAvg = 1000000000L;
|
|
||||||
private double ECNAvg2 = 0L;
|
private double ECNAvg2 = 0L;
|
||||||
private double alpha=0;
|
private double alpha=0;
|
||||||
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
private volatile AtomicLong ECNSize = new AtomicLong(0);
|
||||||
private volatile AtomicLong TotalSize = new AtomicLong(0);
|
private volatile AtomicLong TotalSize = new AtomicLong(0);
|
||||||
private volatile long RTO = 1000000000L;
|
|
||||||
|
private RTTEstimator rttEstimator=new RTTEstimator(100000000L);
|
||||||
|
|
||||||
|
|
||||||
private volatile long window=MIN_WINDOW;
|
private volatile long window=MIN_WINDOW;
|
||||||
@@ -54,14 +51,7 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
} else {
|
} else {
|
||||||
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
RTTMin = (RTTMin * 99999 + latencyns) / 100000;
|
||||||
}
|
}
|
||||||
if (firstUpdate.compareAndSet(true, false)) {
|
rttEstimator.putRTT(latencyns);
|
||||||
RTTAvg = latencyns;
|
|
||||||
RTTVar = latencyns / 2;
|
|
||||||
} else {
|
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - latencyns)) / 4;
|
|
||||||
RTTAvg = (RTTAvg * 7 + latencyns) / 8;
|
|
||||||
}
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);// RTTVar*4
|
|
||||||
|
|
||||||
if(ecn) {
|
if(ecn) {
|
||||||
ECNSize.addAndGet(packetSize);
|
ECNSize.addAndGet(packetSize);
|
||||||
@@ -88,7 +78,7 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
if(windowUsed*3L>=congressWindowSize) {
|
if(windowUsed*3L>=congressWindowSize) {
|
||||||
congressWindowSize+=4000;
|
congressWindowSize+=4096;
|
||||||
updateWindowSize();
|
updateWindowSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,13 +99,13 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRTO() {
|
public long getRTO() {
|
||||||
return RTO;
|
return rttEstimator.getRTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -133,6 +123,15 @@ public class DCTCPCongestionAlgorithm implements CongestionAlgorithm {
|
|||||||
return "DCTCP";
|
return "DCTCP";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBaseRTT() {
|
||||||
|
return rttEstimator.getBaseRTT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCurrentRTT() {
|
||||||
|
return rttEstimator.getCurrentRTT();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,7 @@ public interface DetnetCongestionAlgorithm extends CongestionAlgorithm {
|
|||||||
public void setUpperDelayBound(double upper);
|
public void setUpperDelayBound(double upper);
|
||||||
public void setLowerDelayBound(double lower);
|
public void setLowerDelayBound(double lower);
|
||||||
public void setBurstLimit(double limit);
|
public void setBurstLimit(double limit);
|
||||||
|
public double getUpperDelayBound( );
|
||||||
|
public double getLowerDelayBound();
|
||||||
|
public double getBurstLimit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.kne.cloud.network.congestion;
|
package org.kne.cloud.network.congestion;
|
||||||
|
|
||||||
import org.jctools.queues.MpscArrayQueue;
|
import org.jctools.queues.MessagePassingQueue;
|
||||||
|
import org.jctools.queues.varhandle.MpscVarHandleArrayQueue;
|
||||||
import org.kne.cloud.network.ThreadTool;
|
import org.kne.cloud.network.ThreadTool;
|
||||||
import org.kne.opencl64.Releaser;
|
import org.kne.opencl64.Releaser;
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ class MpscMessageBatcherReleaser<T> extends Releaser<MpscMessageBatcher0<T>> {
|
|||||||
|
|
||||||
class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
||||||
|
|
||||||
private final MpscArrayQueue<T> queue;
|
private final MessagePassingQueue<T> queue;
|
||||||
private final int batchSize;
|
private final int batchSize;
|
||||||
private final long maxDelay;
|
private final long maxDelay;
|
||||||
private volatile Consumer<List<T>> consumer;
|
private volatile Consumer<List<T>> consumer;
|
||||||
@@ -94,7 +95,7 @@ class MpscMessageBatcher0<T> implements Runnable, MessageBatcher<T> {
|
|||||||
public MpscMessageBatcher0(int batchSize, long maxDelay, int queueCapacity) {
|
public MpscMessageBatcher0(int batchSize, long maxDelay, int queueCapacity) {
|
||||||
this.batchSize = batchSize;
|
this.batchSize = batchSize;
|
||||||
this.maxDelay = maxDelay;
|
this.maxDelay = maxDelay;
|
||||||
this.queue = new MpscArrayQueue<>(queueCapacity);
|
this.queue = new MpscVarHandleArrayQueue<>(queueCapacity);
|
||||||
|
|
||||||
this.batchThread = ThreadTool.makeVDaemonThread("MpscMessageBatcher", this);
|
this.batchThread = ThreadTool.makeVDaemonThread("MpscMessageBatcher", this);
|
||||||
this.batchThread.start();
|
this.batchThread.start();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class NOCongestionAlgorithm implements CongestionAlgorithm{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
// TODO 自动生成的方法存根
|
// TODO 自动生成的方法存根
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -63,4 +63,14 @@ public class NOCongestionAlgorithm implements CongestionAlgorithm{
|
|||||||
return "NO";
|
return "NO";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBaseRTT() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCurrentRTT() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package org.kne.cloud.network.congestion;
|
||||||
|
|
||||||
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
|
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||||
|
import org.kne.cloud.network.monitor.ArrayListTimestampMonitor;
|
||||||
|
import org.kne.cloud.network.monitor.DelaySampler;
|
||||||
|
import org.kne.cloud.network.monitor.TimestampMonitor;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程安全的 RTT 平滑与 RTO 计算工具。
|
||||||
|
* 基于 RFC 6298 的 Jacobson/Karels 算法。
|
||||||
|
*
|
||||||
|
* 公式:
|
||||||
|
* RTTAvg = (RTTAvg * 7 + RTTns) / 8
|
||||||
|
* RTTVar = (RTTVar * 3 + |RTTAvg - RTTns|) / 4
|
||||||
|
* RTO = RTTAvg + max(MIN_RTTVAR, RTTVar * 4)
|
||||||
|
*/
|
||||||
|
public class RTTEstimator {
|
||||||
|
|
||||||
|
/** RTTVar 下限(纳秒),防止 RTO 过小。默认 20ms。 */
|
||||||
|
private static final long DEFAULT_MIN_RTTVAR_NS = 20_000_000L;
|
||||||
|
|
||||||
|
private final AtomicLong curr;
|
||||||
|
private final AtomicLong rttAvg;
|
||||||
|
private final AtomicLong rttVar;
|
||||||
|
private final AtomicLong rto;
|
||||||
|
private final AtomicLong basertt;
|
||||||
|
private final AtomicBoolean firstUpdate = new AtomicBoolean(true); // 首次标记
|
||||||
|
private final long minRttVarNs;
|
||||||
|
|
||||||
|
|
||||||
|
private long timewindowmax=500000000L;
|
||||||
|
|
||||||
|
long stime=System.nanoTime();
|
||||||
|
|
||||||
|
public RTTEstimator() {
|
||||||
|
this(DEFAULT_MIN_RTTVAR_NS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RTTEstimator(long minRttVarNs) {
|
||||||
|
this.rttAvg = new AtomicLong(1000000000L);
|
||||||
|
this.rttVar = new AtomicLong(1000000000L);
|
||||||
|
this.curr = new AtomicLong(1000000000L);
|
||||||
|
this.rto = new AtomicLong(1000000000L);
|
||||||
|
this.basertt = new AtomicLong(1000000000L);
|
||||||
|
this.minRttVarNs = minRttVarNs;
|
||||||
|
}
|
||||||
|
private final static long TIME_WINDOW=30000000000L;
|
||||||
|
private final TimestampMonitor<UUID> rttMonitor=new ArrayListTimestampMonitor<UUID>(new HighAccuracyClock(),"RTTMonitor", 100, TIME_WINDOW);
|
||||||
|
private final DelaySampler dsp=new DelaySampler();
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
dsp.update();
|
||||||
|
|
||||||
|
if(dsp.getSnapshotPacketCount()>0&&dsp.getSnapshotTotalDelay()>0) {
|
||||||
|
rttMonitor. recordPacket(KLALBUtils.createGlobalUUID(),0, 0, dsp.getAvgDelayNanos(),dsp.getMinDelayNanos());
|
||||||
|
}
|
||||||
|
|
||||||
|
long time=System.nanoTime();
|
||||||
|
if(time-stime>timewindowmax) {
|
||||||
|
basertt.lazySet( rttMonitor.calculateMinDelay(TIME_WINDOW));
|
||||||
|
stime=time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 更新 RTT 估算值(线程安全)。
|
||||||
|
*
|
||||||
|
* @param rttNs 本次 RTT 测量值(纳秒)
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* 更新 RTT 估算值(线程安全,无锁)。
|
||||||
|
*/
|
||||||
|
public void putRTT(long rttNs) {
|
||||||
|
if (rttNs < 0) {
|
||||||
|
throw new IllegalArgumentException("RTT 不能为负数: " + rttNs);
|
||||||
|
}
|
||||||
|
dsp.recordDelay(rttNs);
|
||||||
|
curr.lazySet(rttNs);
|
||||||
|
// 首次更新:CAS 成功则直接初始化,无锁
|
||||||
|
if (firstUpdate.compareAndSet(true, false)) {
|
||||||
|
rttAvg.set(rttNs);
|
||||||
|
rttVar.set(rttNs / 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 后续更新:CAS 循环保证原子性
|
||||||
|
|
||||||
|
long oldAvg = rttAvg.get();
|
||||||
|
long newAvg = (oldAvg * 7 + rttNs) / 8;
|
||||||
|
|
||||||
|
long delta = Math.abs(oldAvg - rttNs);
|
||||||
|
rttAvg.lazySet(newAvg);
|
||||||
|
long oldVar = rttVar.get();
|
||||||
|
long newVar = (oldVar * 3 + delta) / 4;
|
||||||
|
rttVar.lazySet(newVar);
|
||||||
|
|
||||||
|
rto .lazySet( newAvg + Math.max(minRttVarNs, newVar * 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取平滑 RTT 平均值(纳秒)。
|
||||||
|
*/
|
||||||
|
public long getRTTAvg() {
|
||||||
|
return rttAvg.getPlain();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 RTT 偏差(纳秒)。
|
||||||
|
*/
|
||||||
|
public long getRTTVar() {
|
||||||
|
return rttVar.getPlain();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 RTO(重传超时时间,纳秒)。
|
||||||
|
* RTO = RTTAvg + max(MIN_RTTVAR, RTTVar * 4)
|
||||||
|
*/
|
||||||
|
public long getRTO() {
|
||||||
|
return rto.getPlain();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置估算器(用于连接重建等场景)。
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
rttAvg.set(0);
|
||||||
|
rttVar.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("RttEstimator{avg=%.3fms, var=%.3fms, rto=%.3fms}",
|
||||||
|
rttAvg.get() / 1_000_000.0,
|
||||||
|
rttVar.get() / 1_000_000.0,
|
||||||
|
getRTO() / 1_000_000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCurrentRTT() {
|
||||||
|
return curr.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getBaseRTT() {
|
||||||
|
return basertt.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,10 @@ import java.net.SocketException;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
@@ -13,13 +16,15 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
import org.kne.cloud.network.NetworkPacket;
|
||||||
import org.kne.cloud.network.ThreadTool;
|
import org.kne.cloud.network.ThreadTool;
|
||||||
|
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||||
import org.kne.cloud.network.klalb.SendItem;
|
import org.kne.cloud.network.klalb.SendItem;
|
||||||
import org.kne.concurrent.ThreadParker;
|
import org.kne.concurrent.ThreadParker;
|
||||||
|
|
||||||
public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Closeable, AutoCloseable {
|
public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Closeable, AutoCloseable {
|
||||||
|
private final ScheduledFuture<?> checkerTask;
|
||||||
private ThreadParker tp=new ThreadParker();
|
private ThreadParker tp=new ThreadParker();
|
||||||
|
|
||||||
private Map<K, SendItem<V>> sendMap = new ConcurrentHashMap<>(2048);
|
private volatile Map<K, SendItem<V>> sendMap = new ConcurrentHashMap<>(2048);
|
||||||
private AtomicLong sendWindowUsed=new AtomicLong(0);
|
private AtomicLong sendWindowUsed=new AtomicLong(0);
|
||||||
//private LongAdder sendWindowUsed = new LongAdder();
|
//private LongAdder sendWindowUsed = new LongAdder();
|
||||||
|
|
||||||
@@ -51,13 +56,12 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SendPacketSlidingWindow(CongestionAlgorithm algorithm, long windowSize, int headerCalibrate,
|
public SendPacketSlidingWindow(CongestionAlgorithm algorithm, long windowSize, int headerCalibrate,
|
||||||
boolean removeAtResend) {
|
boolean removeAtResend) {
|
||||||
this.headerCalibrate = headerCalibrate;
|
this.headerCalibrate = headerCalibrate;
|
||||||
this.removeAtResend = removeAtResend;
|
this.removeAtResend = removeAtResend;
|
||||||
this.algorithm = algorithm;
|
this.algorithm = algorithm;
|
||||||
this.windowSize=windowSize;
|
this.windowSize=windowSize;
|
||||||
Thread t = ThreadTool.makeVThread("重路由计时器线程", checker);
|
this.checkerTask=KLALBScheduler.getScheduler().scheduleWithFixedDelay(checker,1,1, TimeUnit.MILLISECONDS);
|
||||||
t.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getWindowSize() {
|
public long getWindowSize() {
|
||||||
@@ -131,16 +135,15 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
algorithm.setCurrentWindowUsed(newWindow);
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
}
|
}
|
||||||
public V ack(K sequence) {
|
public V ack(K sequence) {
|
||||||
return ack(sequence,false);
|
return ack(sequence,0,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public V ack(K sequence,boolean ecn) {
|
public V ack(K sequence,long RTTns,boolean ecn) {
|
||||||
SendItem<V> ipv6;
|
SendItem<V> ipv6;
|
||||||
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
||||||
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
||||||
algorithm.setCurrentWindowUsed(newWindow);
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
long RTTC = System.nanoTime() - ipv6.getSendtime();
|
algorithm.putAck(ipv6.getPacketLength(), RTTns, ecn);
|
||||||
algorithm.putAck(ipv6.getPacketLength(), RTTC, ecn);
|
|
||||||
tp.unpark();
|
tp.unpark();
|
||||||
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
||||||
Lock lockx = lock;
|
Lock lockx = lock;
|
||||||
@@ -162,73 +165,59 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public V ack(K sequence,boolean ecn,long OWDdown) {
|
|
||||||
SendItem<V> ipv6;
|
|
||||||
if ((ipv6 = sendMap.remove(sequence)) != null) {
|
|
||||||
long newWindow =sendWindowUsed.addAndGet(-ipv6.getPacketLength() );
|
|
||||||
algorithm.setCurrentWindowUsed(newWindow);
|
|
||||||
long RTTC = System.nanoTime() - ipv6.getSendtime();
|
|
||||||
algorithm.putAck(ipv6.getPacketLength(), RTTC,OWDdown, ecn);
|
|
||||||
tp.unpark();
|
|
||||||
// System.out.println("remove:"+aseq.getSequence()+" "+sendMap.size());
|
|
||||||
Lock lockx = lock;
|
|
||||||
if (lockx != null) {
|
|
||||||
lockx.lock();
|
|
||||||
try {
|
|
||||||
Condition cds = condition;
|
|
||||||
if (cds != null) {
|
|
||||||
cds.signalAll();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lockx.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ipv6.getPacket();
|
|
||||||
} else {
|
|
||||||
// System.out.println("miss:"+aseq.getSequence()+" "+sendMap.size());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ResendChecker implements Runnable {
|
private class ResendChecker implements Runnable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!closed) {
|
try {
|
||||||
|
if (closed) {
|
||||||
Collection<SendItem<V>> vals = sendMap.values();
|
checkerTask.cancel(false);
|
||||||
for (Iterator<SendItem<V>> iterator = vals.iterator(); iterator.hasNext();) {
|
// 清理资源
|
||||||
SendItem<V> sitm = (SendItem<V>) iterator.next();
|
if (closingConsumer != null) {
|
||||||
long current = System.nanoTime();
|
for (SendItem<V> item : sendMap.values()) {
|
||||||
if (current - sitm.getSendtime() > algorithm.getRTO()) {
|
closingConsumer.accept(item.getPacket());
|
||||||
if (removeAtResend) {
|
|
||||||
iterator.remove();
|
|
||||||
long newWindow = sendWindowUsed.addAndGet((int) -sitm.getPacketLength() );
|
|
||||||
algorithm.setCurrentWindowUsed(newWindow);
|
|
||||||
tp.unpark();
|
|
||||||
} else {
|
|
||||||
sitm.setSendtime(current);
|
|
||||||
}
|
}
|
||||||
V pktr = sitm.getPacket();
|
|
||||||
if (resendConsumer != null)
|
|
||||||
resendConsumer.accept(pktr);
|
|
||||||
}
|
}
|
||||||
}
|
sendMap.clear();
|
||||||
|
sendWindowUsed.set(0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Set<Map.Entry<K,SendItem<V>>> vals = sendMap.entrySet();
|
||||||
|
for (Iterator<Map.Entry<K,SendItem<V>>> iterator = vals.iterator(); iterator.hasNext(); ) {
|
||||||
|
Map.Entry<K,SendItem<V>> entry = (Map.Entry<K,SendItem<V>>) iterator.next();
|
||||||
|
SendItem<V> sitm=entry.getValue();
|
||||||
|
long current = System.nanoTime();
|
||||||
|
long ftime=current - sitm.getSendtime();
|
||||||
|
if (ftime> algorithm.getRTO()) {
|
||||||
|
|
||||||
|
V pktr = sitm.getPacket();
|
||||||
|
|
||||||
|
if (removeAtResend) {
|
||||||
|
SendItem<V> sitm2=sendMap.remove(entry.getKey());
|
||||||
|
if(sitm2!=null) {
|
||||||
|
if (resendConsumer != null)
|
||||||
|
resendConsumer.accept(pktr);
|
||||||
|
algorithm.putLoss(sitm2.getPacketLength(),ftime);
|
||||||
|
long newWindow = sendWindowUsed.addAndGet((int) -sitm2.getPacketLength());
|
||||||
|
algorithm.setCurrentWindowUsed(newWindow);
|
||||||
|
tp.unpark();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sitm.setSendtime(current);
|
||||||
|
if (resendConsumer != null)
|
||||||
|
resendConsumer.accept(pktr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(2);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
// 清理资源
|
|
||||||
if (closingConsumer != null) {
|
|
||||||
for (SendItem<V> item : sendMap.values()) {
|
|
||||||
closingConsumer.accept(item.getPacket());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendMap.clear();
|
|
||||||
sendWindowUsed.set(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package org.kne.cloud.network.congestion;
|
|||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.monitor.DelaySampler;
|
||||||
|
import org.kne.concurrent.SpinLock;
|
||||||
|
|
||||||
public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCongestionAlgorithm {
|
public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCongestionAlgorithm {
|
||||||
|
|
||||||
// 可配置的时延膨胀比上下限 - Vegas2.0核心参数
|
// 可配置的时延膨胀比上下限 - Vegas2.0核心参数
|
||||||
@@ -11,29 +14,26 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
|
|
||||||
private static final long BURST_TIME = 2000000L;
|
private static final long BURST_TIME = 2000000L;
|
||||||
private static final long BIAS = 1000000L;
|
private static final long BIAS = 1000000L;
|
||||||
private static long MIN_WINDOW = 16384;
|
private static long MIN_WINDOW = 8192;
|
||||||
|
|
||||||
|
|
||||||
private Consumer<Long> windowControlConsumer;
|
private Consumer<Long> windowControlConsumer;
|
||||||
|
|
||||||
private long MIN_RTTVAR = 30000000L;
|
private volatile long RTTCurr = 1000000000L; // RTT
|
||||||
private volatile long RTTMin = 1000000000L; // BaseRTT
|
private volatile long RTTMin = 1000000000L; // BaseRTT
|
||||||
private volatile long RTTVar = 1000000000L;
|
|
||||||
private volatile long RTTAvg = 1000000000L;
|
|
||||||
private volatile long RTTAvg2 = 1000000000L; // 当前平滑RTT
|
private volatile long RTTAvg2 = 1000000000L; // 当前平滑RTT
|
||||||
private volatile long RTTTotal = 0;
|
private volatile long RTTTotal = 0;
|
||||||
private volatile long RTTCount = 0;
|
private volatile long RTTCount = 0;
|
||||||
private volatile long RTO = 1000000000L;
|
|
||||||
|
|
||||||
|
private RTTEstimator rttEstimator=new RTTEstimator();
|
||||||
|
|
||||||
private volatile long OWDTotal = 0;
|
|
||||||
private volatile long OWDCount = 0;
|
|
||||||
private volatile long OWDAvg2 = 1000000000L; // 当前平滑OWD
|
|
||||||
private volatile long OWDMin = 1000000000L; // BaseRTT
|
|
||||||
|
|
||||||
private volatile long window = MIN_WINDOW;
|
private volatile long window = MIN_WINDOW;
|
||||||
private volatile long window2 = MIN_WINDOW;
|
private volatile long window2 = MIN_WINDOW;
|
||||||
private volatile long maxwindow = 99999999999L;
|
private volatile long maxwindow = 99999999999L;
|
||||||
|
|
||||||
|
private final SpinLock slock=new SpinLock();
|
||||||
|
|
||||||
public Vegas2CongestionAlgorithm() {
|
public Vegas2CongestionAlgorithm() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
@@ -58,106 +58,13 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putAck(long packetSize, long RTTns, long OWDup, boolean ecn) {
|
|
||||||
if(RTTns<0) {
|
|
||||||
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
|
||||||
}
|
|
||||||
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
|
||||||
if (ecn) {
|
|
||||||
// 当收到ECN时,更激进地减少窗口
|
|
||||||
window2 = Math.max(0, window2 * 3 / 4);
|
|
||||||
if (windowControlConsumer != null) {
|
|
||||||
windowControlConsumer.accept(window2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新最小RTT(BaseRTT)
|
|
||||||
if (RTTns <= RTTMin) {
|
|
||||||
RTTMin = RTTns;
|
|
||||||
} else {
|
|
||||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
|
||||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
|
||||||
RTTMin = (RTTMin * 999 + RTTns) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新最小OWD(BaseOWD)
|
|
||||||
if (OWDup <= OWDMin) {
|
|
||||||
OWDMin = OWDup;
|
|
||||||
} else {
|
|
||||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
|
||||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
|
||||||
OWDMin = (OWDMin * 999 + OWDup) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新平滑RTT估计
|
|
||||||
|
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
|
|
||||||
RTTAvg = (RTTAvg * 7 + RTTns) / 8;
|
|
||||||
|
|
||||||
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
|
|
||||||
|
|
||||||
RTTTotal += RTTns;
|
|
||||||
RTTCount++;
|
|
||||||
|
|
||||||
OWDTotal += OWDup;
|
|
||||||
OWDCount++;
|
|
||||||
|
|
||||||
long curr = System.nanoTime();
|
|
||||||
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
|
||||||
if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
|
|
||||||
long RTTCountx=RTTCount;
|
|
||||||
if (RTTCountx > 0) {
|
|
||||||
long currentRTT = RTTTotal / RTTCountx;
|
|
||||||
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
|
||||||
RTTAvg2=currentRTT;
|
|
||||||
RTTTotal = 0;
|
|
||||||
RTTCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long OWDCountx=OWDCount;
|
|
||||||
if (OWDCountx > 0) {
|
|
||||||
long currentOWD = OWDTotal / OWDCountx;
|
|
||||||
OWDAvg2=currentOWD;
|
|
||||||
OWDTotal = 0;
|
|
||||||
OWDCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ================== Vegas2.0核心逻辑 ==================
|
|
||||||
// 1. 计算时延膨胀比
|
|
||||||
double delayRatio = (double) OWDAvg2 / (double) Math.max(BIAS, OWDMin);
|
|
||||||
//System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
|
|
||||||
// 2. 基于比值的窗口调整(取代原来的基于差值的调整)
|
|
||||||
if (delayRatio > delayUpperBound) {
|
|
||||||
// 时延过高:减小窗口,减少幅度与超标程度成正比
|
|
||||||
window2 -= 4096;
|
|
||||||
} else if (delayRatio < delayLowerBound) {
|
|
||||||
// 时延过低:增大窗口,增加幅度与低于目标程度成正比
|
|
||||||
window2 += 4096;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
// ===================================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateWindowSize();
|
|
||||||
RTTstartTime = curr;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putAck(long packetSize, long RTTns, boolean ecn) {
|
public void putAck(long packetSize, long RTTns, boolean ecn) {
|
||||||
if(RTTns<0) {
|
if(RTTns<0) {
|
||||||
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
|
||||||
}
|
}
|
||||||
|
this.RTTCurr=RTTns;
|
||||||
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
// 处理ECN信号 - 将其视为强烈的拥塞信号
|
||||||
if (ecn) {
|
if (ecn) {
|
||||||
// 当收到ECN时,更激进地减少窗口
|
// 当收到ECN时,更激进地减少窗口
|
||||||
@@ -167,63 +74,53 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新最小RTT(BaseRTT)
|
|
||||||
if (RTTns <= RTTMin) {
|
|
||||||
RTTMin = RTTns;
|
|
||||||
} else {
|
|
||||||
// 缓慢适应:当网络路径真正变化时,BaseRTT应能缓慢更新
|
|
||||||
// 这里使用极慢的衰减因子,只有在持续观测到更低RTT时才快速更新
|
|
||||||
RTTMin = (RTTMin * 999 + RTTns) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新平滑RTT估计
|
// 更新平滑RTT估计
|
||||||
|
rttEstimator.putRTT(RTTns);
|
||||||
RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
|
|
||||||
RTTAvg = (RTTAvg * 7 + RTTns) / 8;
|
|
||||||
|
|
||||||
|
|
||||||
RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
|
|
||||||
|
|
||||||
RTTTotal += RTTns;
|
RTTTotal += RTTns;
|
||||||
RTTCount++;
|
RTTCount++;
|
||||||
|
if(slock.tryLock())try {
|
||||||
|
long curr = System.nanoTime();
|
||||||
|
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
||||||
|
if (curr - RTTstartTime > Math.max(BIAS, 2 * RTTMin)) {
|
||||||
|
rttEstimator.update();
|
||||||
|
RTTMin = rttEstimator.getBaseRTT();
|
||||||
|
|
||||||
long curr = System.nanoTime();
|
|
||||||
// 每个RTT周期调整一次窗口(使用当前估计的RTT)
|
|
||||||
if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
|
|
||||||
long RTTCountx=RTTCount;
|
|
||||||
if (RTTCountx > 0) {
|
|
||||||
long currentRTT = RTTTotal / RTTCountx;
|
|
||||||
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
|
||||||
RTTAvg2=currentRTT;
|
|
||||||
RTTTotal = 0;
|
|
||||||
RTTCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================== Vegas2.0核心逻辑 ==================
|
long RTTCountx = RTTCount;
|
||||||
// 1. 计算时延膨胀比
|
if (RTTCountx > 0) {
|
||||||
double delayRatio = (double) RTTAvg2 / (double) Math.max(BIAS, RTTMin);
|
long currentRTT = RTTTotal / RTTCountx;
|
||||||
//System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
|
//RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4; // 平滑当前RTT
|
||||||
// 2. 基于比值的窗口调整(取代原来的基于差值的调整)
|
RTTAvg2 = currentRTT;
|
||||||
if (delayRatio > delayUpperBound) {
|
RTTTotal = 0;
|
||||||
// 时延过高:减小窗口,减少幅度与超标程度成正比
|
RTTCount = 0;
|
||||||
window2 -= 4096;
|
}
|
||||||
} else if (delayRatio < delayLowerBound) {
|
|
||||||
// 时延过低:增大窗口,增加幅度与低于目标程度成正比
|
// ================== Vegas2.0核心逻辑 ==================
|
||||||
window2 += 4096;
|
// 1. 计算时延膨胀比
|
||||||
} else {
|
double delayRatio = (double) RTTAvg2 / (double) Math.max(BIAS, RTTMin);
|
||||||
|
//System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
|
||||||
|
// 2. 基于比值的窗口调整(取代原来的基于差值的调整)
|
||||||
|
if (delayRatio > delayUpperBound) {
|
||||||
|
// 时延过高:减小窗口,减少幅度与超标程度成正比
|
||||||
|
window2 = window2 - 4096;
|
||||||
|
} else if (delayRatio < delayLowerBound) {
|
||||||
|
// 时延过低:增大窗口,增加幅度与低于目标程度成正比
|
||||||
|
window2 = window2 + 4096;
|
||||||
|
} else {
|
||||||
|
//window2=window2+4096
|
||||||
|
}
|
||||||
|
// ===================================================
|
||||||
|
|
||||||
|
|
||||||
|
updateWindowSize();
|
||||||
|
RTTstartTime = curr;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// ===================================================
|
}finally{
|
||||||
|
slock.unlock();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateWindowSize();
|
|
||||||
RTTstartTime = curr;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,12 +142,12 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putLoss(long packetSize, long lossns, int losscounter) {
|
public void putLoss(long packetSize, long lossns) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRTO() {
|
public long getRTO() {
|
||||||
return RTO;
|
return rttEstimator.getRTO();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -269,12 +166,14 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getBaseRTT() {
|
public long getBaseRTT() {
|
||||||
return RTTMin;
|
return rttEstimator.getBaseRTT();
|
||||||
}
|
}
|
||||||
|
public long getAvgRTT() {
|
||||||
public long getCurrentRTT() {
|
|
||||||
return RTTAvg2;
|
return RTTAvg2;
|
||||||
}
|
}
|
||||||
|
public long getCurrentRTT() {
|
||||||
|
return RTTCurr;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUpperDelayBound(double upper) {
|
public void setUpperDelayBound(double upper) {
|
||||||
@@ -295,4 +194,19 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
|
|||||||
return "Vegas2";
|
return "Vegas2";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getUpperDelayBound() {
|
||||||
|
return delayUpperBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLowerDelayBound() {
|
||||||
|
return delayLowerBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getBurstLimit() {
|
||||||
|
return burstLimit;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package org.kne.cloud.network.ipv6;
|
package org.kne.cloud.network.ipv6;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@@ -10,7 +13,21 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
|||||||
private CopyOnWriteArraySet<IPv6LinkStateListener> listeners = new CopyOnWriteArraySet<>();
|
private CopyOnWriteArraySet<IPv6LinkStateListener> listeners = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
private SRv6Router srv6Router;
|
private SRv6Router srv6Router;
|
||||||
|
private final boolean loopback;
|
||||||
|
|
||||||
|
private final boolean filter;
|
||||||
|
|
||||||
|
|
||||||
|
public AbstractIPv6NetworkLink(boolean loopback) {
|
||||||
|
super();
|
||||||
|
this.loopback = loopback;
|
||||||
|
this.filter = false;
|
||||||
|
}
|
||||||
|
public AbstractIPv6NetworkLink(boolean loopback, boolean filter) {
|
||||||
|
super();
|
||||||
|
this.loopback = loopback;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
public SRv6Router getSrv6Router() {
|
public SRv6Router getSrv6Router() {
|
||||||
return srv6Router;
|
return srv6Router;
|
||||||
@@ -53,8 +70,54 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> receiveConsumer;
|
private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> receiveConsumer;
|
||||||
|
|
||||||
|
private Supplier<Long> costSupplier;
|
||||||
@Override
|
@Override
|
||||||
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink,Supplier< IPv6Packet>> receiveConsumer) {
|
public void setReceiveConsumer(BiConsumer<IPv6NetworkLink,Supplier< IPv6Packet>> receiveConsumer) {
|
||||||
this.receiveConsumer = receiveConsumer;
|
this.receiveConsumer = receiveConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLoopBack() {
|
||||||
|
return loopback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Supplier<Long> getCostSupplier() {
|
||||||
|
return costSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCostSupplier(Supplier<Long> costSupplier) {
|
||||||
|
this.costSupplier = costSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RouteItem> getRouteItems() {
|
||||||
|
List<RouteItem> rlist = new ArrayList<>();
|
||||||
|
if(isLoopBack()) {
|
||||||
|
for(IPv6AddressGroup group:getAddressGroups()) {
|
||||||
|
rlist.add(new RouteItem(new IPv6AddressGroup(group.getAddress(), 128),
|
||||||
|
group.getAddress(), this, RouteItem.DIRECT, 0, 0, null, "D"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isUp()) {
|
||||||
|
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
||||||
|
Neighbor addresses = (Neighbor) iteratorx.next();
|
||||||
|
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
||||||
|
addresses.getAddress().getAddress(), this,RouteItem.SRv6_ENDXSID, 0, 128, costSupplier, "D");
|
||||||
|
rlist.add(ri);
|
||||||
|
|
||||||
|
RouteItem ris = new RouteItem(addresses.getLocator(),
|
||||||
|
addresses.getLocator().getAddress(), this, RouteItem.SRv6_ENDSID, 13, 128,
|
||||||
|
costSupplier, "D");
|
||||||
|
rlist.add(ris);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ public final class IPv6Address implements Comparable<IPv6Address> {
|
|||||||
((long)(bytes[15] & 0xFF));
|
((long)(bytes[15] & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPv6Address(String string) throws UnknownHostException {
|
||||||
|
this((Inet6Address) Inet6Address.getByName(string));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从两个long创建IPv6地址
|
* 从两个long创建IPv6地址
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -67,7 +67,16 @@ public class IPv6AddressGroup implements Comparable<IPv6AddressGroup>{
|
|||||||
prefixLength=in.read();
|
prefixLength=in.read();
|
||||||
}
|
}
|
||||||
public boolean checkMatch(IPv6Address address2) {
|
public boolean checkMatch(IPv6Address address2) {
|
||||||
return address2.equals(address.maskWith(IPv6Address.createMask(prefixLength)));
|
IPv6Address cmsk= IPv6Address.createMask(prefixLength);
|
||||||
|
return address2.maskWith(cmsk).equals(address.maskWith(cmsk));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 返回裁剪后的路由表地址(主机位清零)。
|
||||||
|
* 例如 2001:db8:1::100/64 → 2001:db8:1::/64
|
||||||
|
*/
|
||||||
|
public IPv6AddressGroup toNetworkRoute() {
|
||||||
|
IPv6Address mask = IPv6Address.createMask(prefixLength);
|
||||||
|
IPv6Address maskedAddr = address.maskWith(mask);
|
||||||
|
return new IPv6AddressGroup(maskedAddr, prefixLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,4 +30,5 @@ public interface IPv6NetworkLink {
|
|||||||
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||||
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener);
|
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||||
|
|
||||||
|
public boolean isFilter();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1378,7 +1378,7 @@ public class IPv6Packet extends NetworkPacket {
|
|||||||
// 重路由计数器
|
// 重路由计数器
|
||||||
private AtomicInteger rerouteCounter = new AtomicInteger(0);
|
private AtomicInteger rerouteCounter = new AtomicInteger(0);
|
||||||
|
|
||||||
public AtomicInteger getRerouteCounter() {
|
public AtomicInteger getRouteCounter() {
|
||||||
return rerouteCounter;
|
return rerouteCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class IPv6TUNLoopbackNetworkLink extends AbstractIPv6NetworkLink
|
|||||||
private Lock slok = new SpinLock();
|
private Lock slok = new SpinLock();
|
||||||
|
|
||||||
public IPv6TUNLoopbackNetworkLink(String name,IPv6AddressGroup hostAddress, int mtu, List<InetAddress> dns) throws IOException {
|
public IPv6TUNLoopbackNetworkLink(String name,IPv6AddressGroup hostAddress, int mtu, List<InetAddress> dns) throws IOException {
|
||||||
|
super(true);
|
||||||
if (tun != null)
|
if (tun != null)
|
||||||
throw new IllegalStateException("already open!");
|
throw new IllegalStateException("already open!");
|
||||||
try {
|
try {
|
||||||
@@ -204,13 +205,6 @@ public class IPv6TUNLoopbackNetworkLink extends AbstractIPv6NetworkLink
|
|||||||
LockSupport.unpark(tr);
|
LockSupport.unpark(tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLoopBack() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Neighbor> getNeighborsInfo() {
|
public List<Neighbor> getNeighborsInfo() {
|
||||||
List<Neighbor> hs = new ArrayList<>();
|
List<Neighbor> hs = new ArrayList<>();
|
||||||
@@ -219,10 +213,6 @@ public class IPv6TUNLoopbackNetworkLink extends AbstractIPv6NetworkLink
|
|||||||
return hs;
|
return hs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @Override public boolean isCongress(IPv6Packet iPv6Packet,double scale) {
|
|
||||||
* return sendQueue.size() > 1000*scale; }
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -255,27 +245,4 @@ public class IPv6TUNLoopbackNetworkLink extends AbstractIPv6NetworkLink
|
|||||||
return List.of(hostAddress);
|
return List.of(hostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RouteItem> getRouteItems() {
|
|
||||||
List<RouteItem> rlist = new ArrayList<>();
|
|
||||||
|
|
||||||
for (IPv6AddressGroup grp : getAddressGroups()) {
|
|
||||||
rlist.add(new RouteItem(new IPv6AddressGroup(grp.getAddress(), 128), grp.getAddress(), this, "Direct", 0, 1,
|
|
||||||
null, "D", true));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
|
||||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
|
||||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
|
||||||
addresses.getAddress().getAddress(), this, "Direct", 0, 128, null, "D", false);
|
|
||||||
rlist.add(ri);
|
|
||||||
|
|
||||||
RouteItem ris = new RouteItem(addresses.getLocator(), addresses.getLocator().getAddress(), this,
|
|
||||||
"KLALB SRv6", 13, 128, null, "D", false);
|
|
||||||
rlist.add(ris);
|
|
||||||
|
|
||||||
}
|
|
||||||
return rlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public class LoopbackIPv6NetworkLink extends AbstractIPv6NetworkLink implements
|
|||||||
|
|
||||||
//new Inet6AddressGroup(loopbackAddress, 128) new Inet6AddressGroup((Inet6Address) Inet6Address.getByName("::1"), 128)
|
//new Inet6AddressGroup(loopbackAddress, 128) new Inet6AddressGroup((Inet6Address) Inet6Address.getByName("::1"), 128)
|
||||||
public LoopbackIPv6NetworkLink(List<IPv6AddressGroup> addressGroupsx,SRv6Router router) {
|
public LoopbackIPv6NetworkLink(List<IPv6AddressGroup> addressGroupsx,SRv6Router router) {
|
||||||
|
super(true);
|
||||||
this.addressGroups .addAll( addressGroupsx);
|
this.addressGroups .addAll( addressGroupsx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,10 +55,7 @@ public class LoopbackIPv6NetworkLink extends AbstractIPv6NetworkLink implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLoopBack() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Neighbor> getNeighborsInfo() {
|
public List<Neighbor> getNeighborsInfo() {
|
||||||
@@ -93,29 +91,6 @@ public class LoopbackIPv6NetworkLink extends AbstractIPv6NetworkLink implements
|
|||||||
return rerouteConsumer;
|
return rerouteConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RouteItem> getRouteItems() {
|
|
||||||
List<RouteItem> rlist = new ArrayList<>();
|
|
||||||
for(IPv6AddressGroup group:addressGroups) {
|
|
||||||
rlist.add(new RouteItem(new IPv6AddressGroup(group.getAddress(), 128),
|
|
||||||
group.getAddress(), this, "Direct", 0, 0, null, "D", true));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
|
||||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
|
||||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
|
||||||
addresses.getAddress().getAddress(), this, "Direct", 0, 128, null, "D",
|
|
||||||
false);
|
|
||||||
rlist.add(ri);
|
|
||||||
|
|
||||||
RouteItem ris = new RouteItem(addresses.getLocator(),
|
|
||||||
addresses.getLocator().getAddress(), this, "KLALB SRv6", 13, 128,
|
|
||||||
null, "D", false);
|
|
||||||
rlist.add(ris);
|
|
||||||
|
|
||||||
}
|
|
||||||
return rlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public SRv6Router getRouter() {
|
public SRv6Router getRouter() {
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import java.util.Objects;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
||||||
|
public static final String DIRECT="Direct";
|
||||||
|
public static final String SRv6_ENDSID="SRv6 ENDSID";
|
||||||
|
public static final String SRv6_ENDXSID="SRv6 ENDXSID";
|
||||||
|
public static final String KLALB_SRv6 = "KLALB_SRv6";
|
||||||
|
|
||||||
private IPv6AddressGroup destination;
|
private IPv6AddressGroup destination;
|
||||||
private IPv6Address nexthop;
|
private IPv6Address nexthop;
|
||||||
private IPv6NetworkLink destlink;
|
private IPv6NetworkLink destlink;
|
||||||
@@ -12,7 +17,6 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
|||||||
private long cost;
|
private long cost;
|
||||||
private String flag;
|
private String flag;
|
||||||
private Supplier<Long> costSupplier;
|
private Supplier<Long> costSupplier;
|
||||||
private boolean isLoopback;
|
|
||||||
public String getFlag() {
|
public String getFlag() {
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
@@ -34,21 +38,20 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
|||||||
&& pre == other.pre && Objects.equals(proto, other.proto);
|
&& pre == other.pre && Objects.equals(proto, other.proto);
|
||||||
}
|
}
|
||||||
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
||||||
long cost,String flag,boolean isLoopback) {
|
long cost,String flag) {
|
||||||
super();
|
super();
|
||||||
this.destination = destination;
|
this.destination = destination.toNetworkRoute();
|
||||||
this.nexthop = nexthop;
|
this.nexthop = nexthop;
|
||||||
this.destlink = destlink;
|
this.destlink = destlink;
|
||||||
this.proto = proto;
|
this.proto = proto;
|
||||||
this.pre = pre;
|
this.pre = pre;
|
||||||
this.cost = cost;
|
this.cost = cost;
|
||||||
this.flag=flag;
|
this.flag=flag;
|
||||||
this.isLoopback=isLoopback;
|
|
||||||
}
|
}
|
||||||
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
public RouteItem(IPv6AddressGroup destination, IPv6Address nexthop, IPv6NetworkLink destlink, String proto, int pre,
|
||||||
long cost,Supplier<Long> costSupplier,String flag,boolean isLoopback) {
|
long cost,Supplier<Long> costSupplier,String flag) {
|
||||||
super();
|
super();
|
||||||
this.destination = destination;
|
this.destination = destination.toNetworkRoute();
|
||||||
this.nexthop = nexthop;
|
this.nexthop = nexthop;
|
||||||
this.destlink = destlink;
|
this.destlink = destlink;
|
||||||
this.proto = proto;
|
this.proto = proto;
|
||||||
@@ -56,7 +59,6 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
|||||||
this.cost = cost;
|
this.cost = cost;
|
||||||
this.costSupplier=costSupplier;
|
this.costSupplier=costSupplier;
|
||||||
this.flag=flag;
|
this.flag=flag;
|
||||||
this.isLoopback=isLoopback;
|
|
||||||
}
|
}
|
||||||
public IPv6AddressGroup getDestination() {
|
public IPv6AddressGroup getDestination() {
|
||||||
return destination;
|
return destination;
|
||||||
@@ -73,9 +75,6 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
|
|||||||
public int getPre() {
|
public int getPre() {
|
||||||
return pre;
|
return pre;
|
||||||
}
|
}
|
||||||
public boolean isLoopback() {
|
|
||||||
return isLoopback;
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getDestination()+"\t"+getProto()+"\t"+getPre()+"\t"+getCost()+"\t"+getFlag()+"\t"+getNexthop()+"\t"+getDestlink().getName();
|
return getDestination()+"\t"+getProto()+"\t"+getPre()+"\t"+getCost()+"\t"+getFlag()+"\t"+getNexthop()+"\t"+getDestlink().getName();
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ import org.kne.cloud.network.ipv6.RouteItem;
|
|||||||
|
|
||||||
public abstract class AbstractControlledIPv6NetworkLink extends AbstractIPv6NetworkLink implements ControlledIPv6NetworkLink{
|
public abstract class AbstractControlledIPv6NetworkLink extends AbstractIPv6NetworkLink implements ControlledIPv6NetworkLink{
|
||||||
|
|
||||||
|
public AbstractControlledIPv6NetworkLink(boolean loopback) {
|
||||||
|
super(loopback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class CONST {
|
|||||||
|
|
||||||
public static final String KLALB_S_RV6 = "KLALB_SRv6";
|
public static final String KLALB_S_RV6 = "KLALB_SRv6";
|
||||||
|
|
||||||
|
public static final String KLTP_VIRTUAL_SOCKET_NAME="kltp";
|
||||||
|
|
||||||
public static final int itemwidth = 1000;
|
public static final int itemwidth = 1000;
|
||||||
public static final int linepanelheight = 41;
|
public static final int linepanelheight = 41;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.google.gson.JsonDeserializer;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
import com.google.gson.JsonSerializationContext;
|
import com.google.gson.JsonSerializationContext;
|
||||||
import com.google.gson.JsonSerializer;
|
import com.google.gson.JsonSerializer;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
@@ -61,6 +62,7 @@ public class KLALBConfigItem {
|
|||||||
String s=jobj.get("Type").getAsString();
|
String s=jobj.get("Type").getAsString();
|
||||||
switch(s) {
|
switch(s) {
|
||||||
case "KLALBController":
|
case "KLALBController":
|
||||||
|
normalizeLegacyControllerKeys(jobj);
|
||||||
return arg2.deserialize(arg0, new TypeToken<KLALBControllerConfigItem>() {}.getType());
|
return arg2.deserialize(arg0, new TypeToken<KLALBControllerConfigItem>() {}.getType());
|
||||||
case "SocketBridge":
|
case "SocketBridge":
|
||||||
return arg2.deserialize(arg0, new TypeToken<SocketBridgeConfigItem>() {}.getType());
|
return arg2.deserialize(arg0, new TypeToken<SocketBridgeConfigItem>() {}.getType());
|
||||||
@@ -70,6 +72,39 @@ public class KLALBConfigItem {
|
|||||||
}
|
}
|
||||||
throw new JsonParseException("not a object:"+arg0);
|
throw new JsonParseException("not a object:"+arg0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将历史命名错误的配置键归一化为当前键名(仅在当前键名不存在时生效):
|
||||||
|
* openConnections/lineTable → externalEndpoints,
|
||||||
|
* denyConnectionQuery/denyLineTableQuery → denyExternalEndpointQuery,
|
||||||
|
* denyConnectionBroadcast/denyLineTableBroadcast → denyExternalEndpointBroadcast。
|
||||||
|
*/
|
||||||
|
private void normalizeLegacyControllerKeys(JsonObject jobj) {
|
||||||
|
renameLegacyKey(jobj,"externalEndpoints","openConnections","OpenConnections","lineTable","LineTable");
|
||||||
|
renameLegacyKey(jobj,"denyExternalEndpointQuery","denyConnectionQuery","denyLineTableQuery");
|
||||||
|
renameLegacyKey(jobj,"denyExternalEndpointBroadcast","denyConnectionBroadcast","denyLineTableBroadcast");
|
||||||
|
if (!jobj.has("webListen") && jobj.has("webPort") && !jobj.get("webPort").isJsonNull()) {
|
||||||
|
int port = jobj.get("webPort").getAsInt();
|
||||||
|
jobj.add("webListen", new JsonPrimitive("http://0.0.0.0:" + port));
|
||||||
|
}
|
||||||
|
jobj.remove("webPort");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renameLegacyKey(JsonObject jobj, String newKey, String... legacyKeys) {
|
||||||
|
if (jobj.has(newKey)) {
|
||||||
|
for (String legacyKey : legacyKeys) {
|
||||||
|
jobj.remove(legacyKey);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String legacyKey : legacyKeys) {
|
||||||
|
if (jobj.has(legacyKey)) {
|
||||||
|
jobj.add(newKey, jobj.get(legacyKey));
|
||||||
|
jobj.remove(legacyKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static JsonSerializer<KLALBConfigItem>getDefaultJsonSerializer(){
|
public static JsonSerializer<KLALBConfigItem>getDefaultJsonSerializer(){
|
||||||
|
|||||||
@@ -17,14 +17,8 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
@@ -67,7 +61,7 @@ public class KLALBController {
|
|||||||
public HighAccuracyClock getClock() {
|
public HighAccuracyClock getClock() {
|
||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
private final long TIME_WINDOW=2000000000L;
|
private final long TIME_WINDOW=30000000000L;
|
||||||
private SpeedAndTrafficMonitorDataImpl linkMonitor = new SpeedAndTrafficMonitorDataImpl(
|
private SpeedAndTrafficMonitorDataImpl linkMonitor = new SpeedAndTrafficMonitorDataImpl(
|
||||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100,TIME_WINDOW ),
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100,TIME_WINDOW ),
|
||||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
||||||
@@ -76,7 +70,7 @@ public class KLALBController {
|
|||||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100, TIME_WINDOW),
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100, TIME_WINDOW),
|
||||||
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
||||||
|
|
||||||
private List<MultiProtocolSocketAddress> selflineTable = new ArrayList<>();
|
private List<MultiProtocolSocketAddress> externalEndpoints = new ArrayList<>();
|
||||||
|
|
||||||
private List<MultiProtocolSocketAddress> listensSocketAddress = new CopyOnWriteArrayList<>();
|
private List<MultiProtocolSocketAddress> listensSocketAddress = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
@@ -86,7 +80,7 @@ public class KLALBController {
|
|||||||
private static final boolean debug=false;
|
private static final boolean debug=false;
|
||||||
private static final boolean showpacket = false;
|
private static final boolean showpacket = false;
|
||||||
|
|
||||||
private static final int PREFIX = 128;// 112
|
private static final int PREFIX = 128;
|
||||||
private static final int DISCOVERY_PORT = 4569;
|
private static final int DISCOVERY_PORT = 4569;
|
||||||
|
|
||||||
private static List<IPMulticastDiscovery> ipmd = new ArrayList<>();
|
private static List<IPMulticastDiscovery> ipmd = new ArrayList<>();
|
||||||
@@ -104,23 +98,9 @@ public class KLALBController {
|
|||||||
public List<InetAddress> getDnsAddresses() {
|
public List<InetAddress> getDnsAddresses() {
|
||||||
return dnsAddresses;
|
return dnsAddresses;
|
||||||
}
|
}
|
||||||
private ScheduledExecutorService scheduleTimer=Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(),new ThreadFactory() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Thread newThread(Runnable r) {
|
|
||||||
return ThreadTool.makeVDaemonThreadIfSupport("计时器线程", r);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public ScheduledExecutorService getScheduleTimer() {
|
|
||||||
return scheduleTimer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Timer twk = new Timer("网卡检测扫描计时器", true);
|
|
||||||
|
|
||||||
|
|
||||||
|
private Runnable tsk1 = new Runnable() {
|
||||||
private TimerTask tsk1 = new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -137,9 +117,9 @@ public class KLALBController {
|
|||||||
MultiProtocolSocketAddress bind = new MultiProtocolSocketAddress(tcpl.getProtocol(),
|
MultiProtocolSocketAddress bind = new MultiProtocolSocketAddress(tcpl.getProtocol(),
|
||||||
inetAddress.getHostAddress(), tcpl.getPort());
|
inetAddress.getHostAddress(), tcpl.getPort());
|
||||||
// System.out.println(bind);
|
// System.out.println(bind);
|
||||||
synchronized (selflineTable) {
|
synchronized (externalEndpoints) {
|
||||||
if (!selflineTable.contains(bind)) {
|
if (!externalEndpoints.contains(bind)) {
|
||||||
selflineTable.add(bind);
|
externalEndpoints.add(bind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +190,7 @@ public class KLALBController {
|
|||||||
for (Iterator<IPMulticastDiscovery> iterator = ipmd.iterator(); iterator.hasNext(); ) {
|
for (Iterator<IPMulticastDiscovery> iterator = ipmd.iterator(); iterator.hasNext(); ) {
|
||||||
IPMulticastDiscovery ipMulticastDiscovery = (IPMulticastDiscovery) iterator.next();
|
IPMulticastDiscovery ipMulticastDiscovery = (IPMulticastDiscovery) iterator.next();
|
||||||
if (ipMulticastDiscovery.isClosed() || (!ipMulticastDiscovery.getInterface().isUp())
|
if (ipMulticastDiscovery.isClosed() || (!ipMulticastDiscovery.getInterface().isUp())
|
||||||
|| (configItem != null && configItem.isDenyLineTableBroadcast())) {
|
|| (configItem != null && configItem.isDenyExternalEndpointBroadcast())) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
try {
|
try {
|
||||||
ipMulticastDiscovery.close();
|
ipMulticastDiscovery.close();
|
||||||
@@ -222,7 +202,7 @@ public class KLALBController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configItem != null && configItem.isDenyLineTableBroadcast()) {
|
if (configItem != null && configItem.isDenyExternalEndpointBroadcast()) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
List<NetworkInterface> interfaceList = networkInterfaceManager.getAllAvaliableNetworkInterface();
|
List<NetworkInterface> interfaceList = networkInterfaceManager.getAllAvaliableNetworkInterface();
|
||||||
@@ -299,14 +279,14 @@ public class KLALBController {
|
|||||||
private boolean checkIsSelf(MultiProtocolSocketAddress inetAddress) throws UnknownHostException {
|
private boolean checkIsSelf(MultiProtocolSocketAddress inetAddress) throws UnknownHostException {
|
||||||
|
|
||||||
return inetAddress.getInetAddress().isAnyLocalAddress() || inetAddress.getInetAddress().isLoopbackAddress()
|
return inetAddress.getInetAddress().isAnyLocalAddress() || inetAddress.getInetAddress().isLoopbackAddress()
|
||||||
|| selflineTable.contains(inetAddress);
|
|| externalEndpoints.contains(inetAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkIsSelfLocator(InetAddress inetAddress) {
|
private boolean checkIsSelfLocator(InetAddress inetAddress) {
|
||||||
return srv6Router.getLocator().getAddress().toInet6Address().equals(inetAddress);
|
return srv6Router.getLocator().getAddress().toInet6Address().equals(inetAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimerTask tsk2 = new TimerTask() {
|
private Runnable tsk2 = new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -339,9 +319,9 @@ public class KLALBController {
|
|||||||
try {
|
try {
|
||||||
InetSocketAddress iaddr = new InetSocketAddress(neighbor.getAddress().toInet6Address(),
|
InetSocketAddress iaddr = new InetSocketAddress(neighbor.getAddress().toInet6Address(),
|
||||||
KLALBRoutingProtocol.DEFAULT_PORT);
|
KLALBRoutingProtocol.DEFAULT_PORT);
|
||||||
apiClient.requestOpenLines(iaddr, (v) -> {
|
apiClient.requestNodeInfoFull(iaddr, (v) -> {
|
||||||
ThreadTool.makeVDaemonThreadIfSupport("线路添加任务", () -> {
|
ThreadTool.makeVDaemonThreadIfSupport("线路添加任务", () -> {
|
||||||
for (MultiProtocolSocketAddress msa : v) {
|
for (MultiProtocolSocketAddress msa : v.getOpenLines()) {
|
||||||
// System.out.print(msa);
|
// System.out.print(msa);
|
||||||
addRemoteLines(msa);
|
addRemoteLines(msa);
|
||||||
}
|
}
|
||||||
@@ -401,8 +381,8 @@ public class KLALBController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<MultiProtocolSocketAddress> getSelflineTable() {
|
public List<MultiProtocolSocketAddress> getExternalEndpoints() {
|
||||||
return selflineTable;
|
return externalEndpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -593,18 +573,18 @@ public class KLALBController {
|
|||||||
lineslock.writeLock().lock();
|
lineslock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
krs.startIO();
|
krs.startIO();
|
||||||
String selflineTable = generateSelfLineTable();
|
String externalEndpointsText = generateExternalEndpointsString();
|
||||||
if (selflineTable != null && !selflineTable.equals(""))
|
if (externalEndpointsText != null && !externalEndpointsText.equals(""))
|
||||||
krs.sendPacket(new ADDLINESPacket(selflineTable));
|
krs.sendPacket(new ADDLINESPacket(externalEndpointsText));
|
||||||
srv6Router.getLinkTabel().add(krs);
|
srv6Router.getLinkTabel().add(krs);
|
||||||
} finally {
|
} finally {
|
||||||
lineslock.writeLock().unlock();
|
lineslock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateSelfLineTable() {
|
private String generateExternalEndpointsString() {
|
||||||
StringBuilder sbd = new StringBuilder();
|
StringBuilder sbd = new StringBuilder();
|
||||||
for (Iterator<MultiProtocolSocketAddress> iterator = selflineTable.iterator(); iterator.hasNext();) {
|
for (Iterator<MultiProtocolSocketAddress> iterator = externalEndpoints.iterator(); iterator.hasNext();) {
|
||||||
MultiProtocolSocketAddress klalbRemoteLine = (MultiProtocolSocketAddress) iterator.next();
|
MultiProtocolSocketAddress klalbRemoteLine = (MultiProtocolSocketAddress) iterator.next();
|
||||||
sbd.append(klalbRemoteLine.toString());
|
sbd.append(klalbRemoteLine.toString());
|
||||||
sbd.append('\n');
|
sbd.append('\n');
|
||||||
@@ -634,7 +614,8 @@ public class KLALBController {
|
|||||||
|
|
||||||
private void loadSRv6ProtocolStack(IPv6AddressGroup selfx, boolean enableVirtualAdapter) {
|
private void loadSRv6ProtocolStack(IPv6AddressGroup selfx, boolean enableVirtualAdapter) {
|
||||||
networkInterfaceManager.getInetAddressesExcept().add(selfx.getAddress().toInet6Address());
|
networkInterfaceManager.getInetAddressesExcept().add(selfx.getAddress().toInet6Address());
|
||||||
srv6Router = new SRv6Router(selfx, clock);
|
IPv6AddressGroup group=new IPv6AddressGroup(selfx.getAddress(),32);
|
||||||
|
srv6Router = new SRv6Router(selfx,group, clock);
|
||||||
if(configItem!=null) {
|
if(configItem!=null) {
|
||||||
srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy()));
|
srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy()));
|
||||||
srv6Router.setDeviceName(configItem.getDeviceName());
|
srv6Router.setDeviceName(configItem.getDeviceName());
|
||||||
@@ -647,13 +628,13 @@ public class KLALBController {
|
|||||||
rawPortBinder= new PortBinder(this.getSelf().getAddress());
|
rawPortBinder= new PortBinder(this.getSelf().getAddress());
|
||||||
System.out.println(" Loaded: SRv6 Stack");
|
System.out.println(" Loaded: SRv6 Stack");
|
||||||
|
|
||||||
String name=(configItem!=null)?configItem.getTUNName():CONST.KLALB_S_RV6;
|
String name = (configItem != null && configItem.getTUNName() != null) ? configItem.getTUNName() : CONST.KLALB_S_RV6;
|
||||||
boolean enableTUN = enableVirtualAdapter && (name != null) && !name.trim().isEmpty() && !name.trim().equalsIgnoreCase("null");
|
boolean isEnabled = configItem == null || configItem.isEnableTUN();
|
||||||
|
boolean enableTUN = enableVirtualAdapter && isEnabled && (name != null) && !name.trim().isEmpty() && !name.trim().equalsIgnoreCase("null");
|
||||||
if (enableTUN) {
|
if (enableTUN) {
|
||||||
Thread t=new Thread(()->{
|
Thread t=new Thread(()->{
|
||||||
try {
|
try {
|
||||||
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),
|
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),group, SRv6Router.MTU, dnsAddresses);
|
||||||
new IPv6AddressGroup(srv6Router.getLocator().getAddress(), 32), SRv6Router.MTU, dnsAddresses);
|
|
||||||
tunlink.setMonitor(datatMonitor);
|
tunlink.setMonitor(datatMonitor);
|
||||||
// srv6Router.getLinkTabel().add(tunlink);
|
// srv6Router.getLinkTabel().add(tunlink);
|
||||||
srv6Router.getinLoopback().setFallbackLink(tunlink);
|
srv6Router.getinLoopback().setFallbackLink(tunlink);
|
||||||
@@ -685,8 +666,8 @@ public class KLALBController {
|
|||||||
context.syncToSystem();
|
context.syncToSystem();
|
||||||
// System.out.println(context);
|
// System.out.println(context);
|
||||||
try {
|
try {
|
||||||
NTPv4Protocol nvc = new NTPv4Protocol(context,
|
/*NTPv4Protocol nvc = new NTPv4Protocol(context,
|
||||||
new MultiProtocolSocketAddress(iproxyname + "_Datagram","0.0.0.0",123));
|
new MultiProtocolSocketAddress(iproxyname + "datagram","0.0.0.0",123));
|
||||||
srv6Router.addSRv6RouterListener(new SRv6RouterListener() {
|
srv6Router.addSRv6RouterListener(new SRv6RouterListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -697,7 +678,7 @@ public class KLALBController {
|
|||||||
for (Neighbor neighbor : nb) {
|
for (Neighbor neighbor : nb) {
|
||||||
if (neighbor.getLocator() != null)
|
if (neighbor.getLocator() != null)
|
||||||
sp.add(new NTPPeer(
|
sp.add(new NTPPeer(
|
||||||
new MultiProtocolSocketAddress(iproxyname + "_Datagram",
|
new MultiProtocolSocketAddress(iproxyname + "datagram",
|
||||||
neighbor.getLocator().getAddress().toString(), 123),
|
neighbor.getLocator().getAddress().toString(), 123),
|
||||||
NTPv4Packet.NTP_SYMMETRIC_ACTIVE));
|
NTPv4Packet.NTP_SYMMETRIC_ACTIVE));
|
||||||
|
|
||||||
@@ -717,7 +698,7 @@ public class KLALBController {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
|
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
|
||||||
|
|
||||||
System.out.println(" Loaded: NTP Module");
|
System.out.println(" Loaded: NTP Module");
|
||||||
@@ -733,8 +714,8 @@ public class KLALBController {
|
|||||||
private void loadController() {
|
private void loadController() {
|
||||||
this.apiServer = new KLALBRoutingProtocolAPIServer(routingProtocol, this);
|
this.apiServer = new KLALBRoutingProtocolAPIServer(routingProtocol, this);
|
||||||
this.apiClient = new KLALBRoutingProtocolAPIClient(routingProtocol);
|
this.apiClient = new KLALBRoutingProtocolAPIClient(routingProtocol);
|
||||||
twk.schedule(tsk1, 5000, 5000);
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(tsk1, 5000, 5000,TimeUnit.MILLISECONDS);
|
||||||
twk.schedule(tsk2, 5000, 5000);
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(tsk2, 5000, 5000,TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KLALBController() {
|
public KLALBController() {
|
||||||
@@ -752,17 +733,12 @@ public class KLALBController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void initKLALB(boolean enableVirtualAdapter, IPv6AddressGroup selfg) {
|
protected void initKLALB(boolean enableVirtualAdapter, IPv6AddressGroup selfg) {
|
||||||
ThreadTool.makeVDaemonThread("线路性能采样线程", ()->{
|
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
|
||||||
while(true) {
|
|
||||||
linkMonitor.update();
|
linkMonitor.update();
|
||||||
datatMonitor.update();
|
},1,1,TimeUnit.MILLISECONDS);
|
||||||
try {
|
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
|
||||||
Thread.sleep(1);
|
datatMonitor.update();
|
||||||
} catch (InterruptedException e) {
|
},1,1,TimeUnit.MILLISECONDS);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
|
loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
|
||||||
loadController();
|
loadController();
|
||||||
}
|
}
|
||||||
@@ -800,18 +776,18 @@ public class KLALBController {
|
|||||||
getIpv6Router().setASN(vasn);
|
getIpv6Router().setASN(vasn);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MultiProtocolSocketAddress> linele = configItem.getLineTable();
|
List<MultiProtocolSocketAddress> linele = configItem.getExternalEndpoints();
|
||||||
if (linele != null) {
|
if (linele != null) {
|
||||||
getSelflineTable().addAll(linele);
|
getExternalEndpoints().addAll(linele);
|
||||||
}
|
}
|
||||||
List<MultiProtocolSocketAddress> linetoc = configItem.getConnectLineTable();
|
List<MultiProtocolSocketAddress> linetoc = configItem.getAutoConnections();
|
||||||
if (linetoc != null) {
|
if (linetoc != null) {
|
||||||
linetoc.forEach((aline) -> {
|
linetoc.forEach((aline) -> {
|
||||||
addRemoteLines(aline);
|
addRemoteLines(aline);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MultiProtocolSocketAddress> ntps = configItem.getNtpServerTable();
|
List<MultiProtocolSocketAddress> ntps = configItem.getNtpServers();
|
||||||
if (ntps != null) {
|
if (ntps != null) {
|
||||||
getNTPTable().addAll(ntps);
|
getNTPTable().addAll(ntps);
|
||||||
}
|
}
|
||||||
@@ -855,9 +831,8 @@ public class KLALBController {
|
|||||||
return srv6Router;
|
return srv6Router;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Timer trtr = new Timer("路由表刷新计时器", true);
|
|
||||||
{
|
{
|
||||||
trtr.scheduleAtFixedRate(new TimerTask() {
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -868,9 +843,9 @@ public class KLALBController {
|
|||||||
srv6Router.updateRouteTabel();
|
srv6Router.updateRouteTabel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100, 100);
|
}, 100, 100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
trtr.scheduleAtFixedRate(new TimerTask() {
|
KLALBScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -879,7 +854,7 @@ public class KLALBController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}, 10, 10);
|
}, 1, 1,TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPv6Packet createPacketToAddress(IPv6Address addr, int flowlabel, IPv6Packet.IPv6Payload packet) {
|
public IPv6Packet createPacketToAddress(IPv6Address addr, int flowlabel, IPv6Packet.IPv6Payload packet) {
|
||||||
@@ -977,8 +952,8 @@ public class KLALBController {
|
|||||||
|
|
||||||
|
|
||||||
public void registerToProxyTypeAs(String proxyname) {
|
public void registerToProxyTypeAs(String proxyname) {
|
||||||
MultiProtocolSocketAddress.getSocketTypeRegister().put(proxyname + "_Stream", streamSocketType);
|
MultiProtocolSocketAddress.getSocketTypeRegister().put(proxyname + "stream", streamSocketType);
|
||||||
MultiProtocolSocketAddress.getSocketTypeRegister().put(proxyname + "_Datagram", datagramSocketType);
|
MultiProtocolSocketAddress.getSocketTypeRegister().put(proxyname + "datagram", datagramSocketType);
|
||||||
// ProxyProfileEntry.getRegister().put(proxyname, this);
|
// ProxyProfileEntry.getRegister().put(proxyname, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
private MultiProtocolSocketAddress TCPListen=new MultiProtocolSocketAddress("0.0.0.0",4565);
|
private MultiProtocolSocketAddress TCPListen=new MultiProtocolSocketAddress("0.0.0.0",4565);
|
||||||
private MultiProtocolSocketAddress UDPListen=new MultiProtocolSocketAddress("udp","0.0.0.0",4565);
|
private MultiProtocolSocketAddress UDPListen=new MultiProtocolSocketAddress("udp","0.0.0.0",4565);
|
||||||
private String VirtualSocketName;
|
private String VirtualSocketName;
|
||||||
private List<MultiProtocolSocketAddress>LineTable=new ArrayList<>();
|
private List<MultiProtocolSocketAddress> externalEndpoints = new ArrayList<>();
|
||||||
private List<MultiProtocolSocketAddress>ConnectLineTable=new ArrayList<>();
|
private List<MultiProtocolSocketAddress> autoConnections = new ArrayList<>();
|
||||||
private List<MultiProtocolSocketAddress>ntpServerTable=new ArrayList<>();
|
private List<MultiProtocolSocketAddress> ntpServers = new ArrayList<>();
|
||||||
private List<String>ExtraRoutes=new ArrayList<>();
|
private List<String> ExtraRoutes = new ArrayList<>();
|
||||||
private boolean denyLineTableQuery=false;
|
private boolean denyExternalEndpointQuery = false;
|
||||||
private boolean denyLineTableBroadcast=false;
|
private boolean denyExternalEndpointBroadcast = false;
|
||||||
private String congestionAlgorithm="BBR";
|
private String congestionAlgorithm="BBR";
|
||||||
private double burstLimit=1.50;
|
private double burstLimit=1.50;
|
||||||
private double delayUpperBound=1.20;
|
private double delayUpperBound=1.20;
|
||||||
@@ -29,10 +29,37 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
private long nagleDelayTime=1000000L;
|
private long nagleDelayTime=1000000L;
|
||||||
private long linkNagleDelayTime=1000000L;
|
private long linkNagleDelayTime=1000000L;
|
||||||
private int linkConnectionsCount=1;
|
private int linkConnectionsCount=1;
|
||||||
|
private boolean enableTUN = true;
|
||||||
private String TUNName=CONST.KLALB_S_RV6;
|
private String TUNName=CONST.KLALB_S_RV6;
|
||||||
private String performanceStrategy="multifill";
|
private String performanceStrategy="multifill";
|
||||||
private String DeviceName;
|
private String DeviceName;
|
||||||
private String DeviceDescription;
|
private String DeviceDescription;
|
||||||
|
private boolean webUI = false;
|
||||||
|
private MultiProtocolSocketAddress webListen = new MultiProtocolSocketAddress("http", "0.0.0.0", 4665);
|
||||||
|
|
||||||
|
public boolean isEnableTUN() {
|
||||||
|
return enableTUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnableTUN(boolean enableTUN) {
|
||||||
|
this.enableTUN = enableTUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWebUI() {
|
||||||
|
return webUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWebUI(boolean webUI) {
|
||||||
|
this.webUI = webUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiProtocolSocketAddress getWebListen() {
|
||||||
|
return webListen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWebListen(MultiProtocolSocketAddress webListen) {
|
||||||
|
this.webListen = webListen;
|
||||||
|
}
|
||||||
|
|
||||||
public String getPerformanceStrategy() {
|
public String getPerformanceStrategy() {
|
||||||
return performanceStrategy;
|
return performanceStrategy;
|
||||||
@@ -177,39 +204,44 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<MultiProtocolSocketAddress> getLineTable() {
|
public List<MultiProtocolSocketAddress> getExternalEndpoints() {
|
||||||
return LineTable;
|
return externalEndpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setExternalEndpoints(List<MultiProtocolSocketAddress> externalEndpoints) {
|
||||||
|
this.externalEndpoints = externalEndpoints;
|
||||||
public void setLineTable(List<MultiProtocolSocketAddress> lineTable) {
|
|
||||||
LineTable = lineTable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MultiProtocolSocketAddress> getAutoConnections() {
|
||||||
|
return autoConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoConnections(List<MultiProtocolSocketAddress> autoConnections) {
|
||||||
|
this.autoConnections = autoConnections;
|
||||||
|
}
|
||||||
|
|
||||||
public List<MultiProtocolSocketAddress> getConnectLineTable() {
|
public List<MultiProtocolSocketAddress> getConnectLineTable() {
|
||||||
return ConnectLineTable;
|
return autoConnections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setConnectLineTable(List<MultiProtocolSocketAddress> connectLineTable) {
|
public void setConnectLineTable(List<MultiProtocolSocketAddress> connectLineTable) {
|
||||||
ConnectLineTable = connectLineTable;
|
this.autoConnections = connectLineTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<MultiProtocolSocketAddress> getNtpServers() {
|
||||||
|
return ntpServers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNtpServers(List<MultiProtocolSocketAddress> ntpServers) {
|
||||||
|
this.ntpServers = ntpServers;
|
||||||
|
}
|
||||||
|
|
||||||
public List<MultiProtocolSocketAddress> getNtpServerTable() {
|
public List<MultiProtocolSocketAddress> getNtpServerTable() {
|
||||||
return ntpServerTable;
|
return ntpServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setNtpServerTable(List<MultiProtocolSocketAddress> ntpServerTable) {
|
public void setNtpServerTable(List<MultiProtocolSocketAddress> ntpServerTable) {
|
||||||
this.ntpServerTable = ntpServerTable;
|
this.ntpServers = ntpServerTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getExtraRoutes() {
|
public List<String> getExtraRoutes() {
|
||||||
@@ -280,23 +312,20 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isDenyLineTableQuery() {
|
public boolean isDenyExternalEndpointQuery() {
|
||||||
return denyLineTableQuery;
|
return denyExternalEndpointQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDenyExternalEndpointQuery(boolean denyExternalEndpointQuery) {
|
||||||
public void setDenyLineTableQuery(boolean denyLineTableQuery) {
|
this.denyExternalEndpointQuery = denyExternalEndpointQuery;
|
||||||
this.denyLineTableQuery = denyLineTableQuery;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDenyExternalEndpointBroadcast() {
|
||||||
public boolean isDenyLineTableBroadcast() {
|
return denyExternalEndpointBroadcast;
|
||||||
return denyLineTableBroadcast;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDenyExternalEndpointBroadcast(boolean denyExternalEndpointBroadcast) {
|
||||||
public void setDenyLineTableBroadcast(boolean denyLineTableBroadcast) {
|
this.denyExternalEndpointBroadcast = denyExternalEndpointBroadcast;
|
||||||
this.denyLineTableBroadcast = denyLineTableBroadcast;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -352,12 +381,12 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
", TCPListen=" + TCPListen +
|
", TCPListen=" + TCPListen +
|
||||||
", UDPListen=" + UDPListen +
|
", UDPListen=" + UDPListen +
|
||||||
", VirtualSocketName='" + VirtualSocketName + '\'' +
|
", VirtualSocketName='" + VirtualSocketName + '\'' +
|
||||||
", LineTable=" + LineTable +
|
", externalEndpoints=" + externalEndpoints +
|
||||||
", ConnectLineTable=" + ConnectLineTable +
|
", autoConnections=" + autoConnections +
|
||||||
", ntpServerTable=" + ntpServerTable +
|
", ntpServers=" + ntpServers +
|
||||||
", ExtraRoutes=" + ExtraRoutes +
|
", ExtraRoutes=" + ExtraRoutes +
|
||||||
", denyLineTableQuery=" + denyLineTableQuery +
|
", denyExternalEndpointQuery=" + denyExternalEndpointQuery +
|
||||||
", denyLineTableBroadcast=" + denyLineTableBroadcast +
|
", denyExternalEndpointBroadcast=" + denyExternalEndpointBroadcast +
|
||||||
", congestionAlgorithm='" + congestionAlgorithm + '\'' +
|
", congestionAlgorithm='" + congestionAlgorithm + '\'' +
|
||||||
", burstLimit=" + burstLimit +
|
", burstLimit=" + burstLimit +
|
||||||
", delayUpperBound=" + delayUpperBound +
|
", delayUpperBound=" + delayUpperBound +
|
||||||
@@ -365,11 +394,14 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
", nagleDelayTime=" + nagleDelayTime +
|
", nagleDelayTime=" + nagleDelayTime +
|
||||||
", linkNagleDelayTime=" + linkNagleDelayTime +
|
", linkNagleDelayTime=" + linkNagleDelayTime +
|
||||||
", linkConnectionsCount=" + linkConnectionsCount +
|
", linkConnectionsCount=" + linkConnectionsCount +
|
||||||
|
", enableTUN=" + enableTUN +
|
||||||
", TUNName='" + TUNName + '\'' +
|
", TUNName='" + TUNName + '\'' +
|
||||||
", performanceStrategy='" + performanceStrategy + '\'' +
|
", performanceStrategy='" + performanceStrategy + '\'' +
|
||||||
", DeviceName='" + DeviceName + '\'' +
|
", DeviceName='" + DeviceName + '\'' +
|
||||||
", DeviceDescription='" + DeviceDescription + '\'' +
|
", DeviceDescription='" + DeviceDescription + '\'' +
|
||||||
", NetworkInterfaceExcepts=" + NetworkInterfaceExcepts +
|
", NetworkInterfaceExcepts=" + NetworkInterfaceExcepts +
|
||||||
|
", webUI=" + webUI +
|
||||||
|
", webListen=" + webListen +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,11 +410,11 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
|
|||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
if (!super.equals(o)) return false;
|
if (!super.equals(o)) return false;
|
||||||
KLALBControllerConfigItem that = (KLALBControllerConfigItem) o;
|
KLALBControllerConfigItem that = (KLALBControllerConfigItem) o;
|
||||||
return nogui == that.nogui && denyLineTableQuery == that.denyLineTableQuery && denyLineTableBroadcast == that.denyLineTableBroadcast && Double.compare(burstLimit, that.burstLimit) == 0 && Double.compare(delayUpperBound, that.delayUpperBound) == 0 && Double.compare(delayLowerBound, that.delayLowerBound) == 0 && nagleDelayTime == that.nagleDelayTime && linkNagleDelayTime == that.linkNagleDelayTime && linkConnectionsCount == that.linkConnectionsCount && Objects.equals(language, that.language) && Objects.equals(VirtualAddress, that.VirtualAddress) && Objects.equals(VirtualASN, that.VirtualASN) && Objects.equals(DNS, that.DNS) && Objects.equals(TCPListen, that.TCPListen) && Objects.equals(UDPListen, that.UDPListen) && Objects.equals(VirtualSocketName, that.VirtualSocketName) && Objects.equals(LineTable, that.LineTable) && Objects.equals(ConnectLineTable, that.ConnectLineTable) && Objects.equals(ntpServerTable, that.ntpServerTable) && Objects.equals(ExtraRoutes, that.ExtraRoutes) && Objects.equals(congestionAlgorithm, that.congestionAlgorithm) && Objects.equals(TUNName, that.TUNName) && Objects.equals(performanceStrategy, that.performanceStrategy) && Objects.equals(DeviceName, that.DeviceName) && Objects.equals(DeviceDescription, that.DeviceDescription) && Objects.equals(NetworkInterfaceExcepts, that.NetworkInterfaceExcepts);
|
return nogui == that.nogui && enableTUN == that.enableTUN && webUI == that.webUI && denyExternalEndpointQuery == that.denyExternalEndpointQuery && denyExternalEndpointBroadcast == that.denyExternalEndpointBroadcast && Double.compare(burstLimit, that.burstLimit) == 0 && Double.compare(delayUpperBound, that.delayUpperBound) == 0 && Double.compare(delayLowerBound, that.delayLowerBound) == 0 && nagleDelayTime == that.nagleDelayTime && linkNagleDelayTime == that.linkNagleDelayTime && linkConnectionsCount == that.linkConnectionsCount && Objects.equals(webListen, that.webListen) && Objects.equals(language, that.language) && Objects.equals(VirtualAddress, that.VirtualAddress) && Objects.equals(VirtualASN, that.VirtualASN) && Objects.equals(DNS, that.DNS) && Objects.equals(TCPListen, that.TCPListen) && Objects.equals(UDPListen, that.UDPListen) && Objects.equals(VirtualSocketName, that.VirtualSocketName) && Objects.equals(externalEndpoints, that.externalEndpoints) && Objects.equals(autoConnections, that.autoConnections) && Objects.equals(ntpServers, that.ntpServers) && Objects.equals(ExtraRoutes, that.ExtraRoutes) && Objects.equals(congestionAlgorithm, that.congestionAlgorithm) && Objects.equals(TUNName, that.TUNName) && Objects.equals(performanceStrategy, that.performanceStrategy) && Objects.equals(DeviceName, that.DeviceName) && Objects.equals(DeviceDescription, that.DeviceDescription) && Objects.equals(NetworkInterfaceExcepts, that.NetworkInterfaceExcepts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), language, nogui, VirtualAddress, VirtualASN, DNS, TCPListen, UDPListen, VirtualSocketName, LineTable, ConnectLineTable, ntpServerTable, ExtraRoutes, denyLineTableQuery, denyLineTableBroadcast, congestionAlgorithm, burstLimit, delayUpperBound, delayLowerBound, nagleDelayTime, linkNagleDelayTime, linkConnectionsCount, TUNName, performanceStrategy, DeviceName, DeviceDescription, NetworkInterfaceExcepts);
|
return Objects.hash(super.hashCode(), language, nogui, VirtualAddress, VirtualASN, DNS, TCPListen, UDPListen, VirtualSocketName, externalEndpoints, autoConnections, ntpServers, ExtraRoutes, denyExternalEndpointQuery, denyExternalEndpointBroadcast, congestionAlgorithm, burstLimit, delayUpperBound, delayLowerBound, nagleDelayTime, linkNagleDelayTime, linkConnectionsCount, enableTUN, TUNName, performanceStrategy, DeviceName, DeviceDescription, NetworkInterfaceExcepts, webUI, webListen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ import org.kne.cloud.network.klalb.ui.UIEnv;
|
|||||||
import org.kne.cloud.network.perf.Kperf;
|
import org.kne.cloud.network.perf.Kperf;
|
||||||
import org.kne.cloud.network.perf.NodeBenchmark;
|
import org.kne.cloud.network.perf.NodeBenchmark;
|
||||||
import org.kne.debug.TimeDebugger;
|
import org.kne.debug.TimeDebugger;
|
||||||
import org.kne.membandboost.MembandBenchmark;
|
import org.kne.membandboost.benchmark.*;;
|
||||||
import org.kne.membandboost.ObjectPoolBandwidthTest;
|
|
||||||
|
|
||||||
public class KLALBMain {
|
public class KLALBMain {
|
||||||
public static KLALBStateGUI3 ksg;
|
public static KLALBStateGUI3 ksg;
|
||||||
@@ -52,13 +51,15 @@ public class KLALBMain {
|
|||||||
}catch(Throwable e) {
|
}catch(Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
if(kpcje.getControllerConfig() != null && kpcje.getControllerConfig().isWebUI()) {
|
||||||
|
kpcje.enableWebServer();
|
||||||
|
}
|
||||||
|
} catch(Throwable e) {
|
||||||
|
System.err.println("Failed to start web server: " + e.getMessage());
|
||||||
|
}
|
||||||
dtb.putTime("UI");
|
dtb.putTime("UI");
|
||||||
//dtb.print();
|
//dtb.print();
|
||||||
/*MultipurposeSocketAddress mpa=new MultipurposeSocketAddress("127.9.9.9", 49573);
|
|
||||||
kpcje.enableRemoteManagement(mpa);
|
|
||||||
System.out.println("远程管理端口已在"+mpa+"端口上开启");*/
|
|
||||||
/*if(true)
|
|
||||||
return;*/
|
|
||||||
ServerSocketChannel kpsvr=KLALBVirtualServerSocketChannel.open(kpcje.getKlalbController());
|
ServerSocketChannel kpsvr=KLALBVirtualServerSocketChannel.open(kpcje.getKlalbController());
|
||||||
kpsvr.bind(new InetSocketAddress("::0", 4564));
|
kpsvr.bind(new InetSocketAddress("::0", 4564));
|
||||||
SocketChannelListener stlr=new SocketChannelListener(kpsvr);
|
SocketChannelListener stlr=new SocketChannelListener(kpsvr);
|
||||||
@@ -84,6 +85,7 @@ public class KLALBMain {
|
|||||||
case "help":
|
case "help":
|
||||||
System.out.println(" help / ?: see help");
|
System.out.println(" help / ?: see help");
|
||||||
System.out.println(" monitor: show monitor GUI");
|
System.out.println(" monitor: show monitor GUI");
|
||||||
|
System.out.println(" web [start|stop|status <port>]: manage web dashboard");
|
||||||
System.out.println(" links-state: query link states");
|
System.out.println(" links-state: query link states");
|
||||||
System.out.println(" links-add <addr:port>: add link");
|
System.out.println(" links-add <addr:port>: add link");
|
||||||
System.out.println(" links-remove <addr:port>: remove link");
|
System.out.println(" links-remove <addr:port>: remove link");
|
||||||
@@ -102,6 +104,42 @@ public class KLALBMain {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "web":
|
||||||
|
if(sc.length >= 2) {
|
||||||
|
String action = sc[1].toLowerCase();
|
||||||
|
if("start".equals(action)) {
|
||||||
|
int p = 4665;
|
||||||
|
if(sc.length >= 3) {
|
||||||
|
try { p = Integer.parseInt(sc[2]); } catch (NumberFormatException ignored) {}
|
||||||
|
} else if(kpcje.getControllerConfig() != null && kpcje.getControllerConfig().getWebListen() != null) {
|
||||||
|
p = kpcje.getControllerConfig().getWebListen().getPort();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
kpcje.enableWebServer(p);
|
||||||
|
System.out.println("Web dashboard started on http://localhost:" + p);
|
||||||
|
} catch(Exception e) {
|
||||||
|
System.out.println("Failed to start web server: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else if("stop".equals(action)) {
|
||||||
|
kpcje.disableWebServer();
|
||||||
|
System.out.println("Web dashboard stopped.");
|
||||||
|
} else if("status".equals(action)) {
|
||||||
|
if(kpcje.isWebServerEnabled()) {
|
||||||
|
System.out.println("Web dashboard is running on port " + kpcje.getWebServer().getPort());
|
||||||
|
} else {
|
||||||
|
System.out.println("Web dashboard is stopped.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("Usage: web [start|stop|status <port>]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(kpcje.isWebServerEnabled()) {
|
||||||
|
System.out.println("Web dashboard is running on port " + kpcje.getWebServer().getPort());
|
||||||
|
} else {
|
||||||
|
System.out.println("Web dashboard is not running. Use 'web start [port]' to start.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "links-state":
|
case "links-state":
|
||||||
System.out.println("links state:");
|
System.out.println("links state:");
|
||||||
//System.out.println("状态\t上传流量\t下载流量\t上传速度\t下载速度\t上传延迟\t下载延迟\t上传抖动\t下载抖动");
|
//System.out.println("状态\t上传流量\t下载流量\t上传速度\t下载速度\t上传延迟\t下载延迟\t上传抖动\t下载抖动");
|
||||||
@@ -200,10 +238,6 @@ public class KLALBMain {
|
|||||||
case "membandbenchmark":
|
case "membandbenchmark":
|
||||||
MembandBenchmark.main(args);
|
MembandBenchmark.main(args);
|
||||||
break;
|
break;
|
||||||
case "memqueuebenchmark":
|
|
||||||
|
|
||||||
ObjectPoolBandwidthTest.main(args);
|
|
||||||
break;
|
|
||||||
//case "$$SYSTEM:":
|
//case "$$SYSTEM:":
|
||||||
//System.out.println();
|
//System.out.println();
|
||||||
//break;
|
//break;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import java.io.FileReader;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
@@ -12,18 +14,25 @@ import org.kne.cloud.network.*;
|
|||||||
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
|
import org.kne.cloud.network.klalb.ui.KLALBStateGUI3;
|
||||||
import org.kne.cloud.network.klalb.ui.Language;
|
import org.kne.cloud.network.klalb.ui.Language;
|
||||||
import org.kne.cloud.network.klalb.ui.UIEnv;
|
import org.kne.cloud.network.klalb.ui.UIEnv;
|
||||||
|
import org.kne.cloud.network.klalb.web.KLALBWebServer;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
public class KLALBProxySystem {
|
public class KLALBProxySystem {
|
||||||
private Set<Proxy> proxys=new HashSet<>();
|
private Set<Proxy> proxys=new HashSet<>();
|
||||||
private KLALBController klalbController;
|
private KLALBController klalbController;
|
||||||
private KLALBRemoteManagement krm;
|
private KLALBWebServer webServer;
|
||||||
private KLALBConfig config;
|
private KLALBConfig config;
|
||||||
private Gson gson;
|
private Gson gson;
|
||||||
private File jsonFile;
|
private File jsonFile;
|
||||||
@@ -31,8 +40,28 @@ public class KLALBProxySystem {
|
|||||||
GsonBuilder gb=new GsonBuilder().setPrettyPrinting();
|
GsonBuilder gb=new GsonBuilder().setPrettyPrinting();
|
||||||
MultiProtocolSocketAddress.registerToGsonBuilder(gb);
|
MultiProtocolSocketAddress.registerToGsonBuilder(gb);
|
||||||
KLALBConfigItem.registerToGsonBuilder(gb);
|
KLALBConfigItem.registerToGsonBuilder(gb);
|
||||||
|
gb.registerTypeAdapter(InetAddress.class, new JsonSerializer<InetAddress>() {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(InetAddress src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
|
return new JsonPrimitive(src.getHostAddress());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
gb.registerTypeAdapter(InetAddress.class, new JsonDeserializer<InetAddress>() {
|
||||||
|
@Override
|
||||||
|
public InetAddress deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
try {
|
||||||
|
return InetAddress.getByName(json.getAsString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new JsonParseException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
gson=gb.create();
|
gson=gb.create();
|
||||||
}
|
}
|
||||||
|
public Gson getGson() {
|
||||||
|
return gson;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<Proxy> getProxys() {
|
public Set<Proxy> getProxys() {
|
||||||
return proxys;
|
return proxys;
|
||||||
}
|
}
|
||||||
@@ -55,30 +84,38 @@ public class KLALBProxySystem {
|
|||||||
public KLALBProxySystem() {
|
public KLALBProxySystem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableRemoteManagement() throws IOException {
|
public void enableWebServer() throws IOException {
|
||||||
if(krm==null) {
|
KLALBControllerConfigItem cci = getControllerConfig();
|
||||||
krm=new KLALBRemoteManagement(this);
|
MultiProtocolSocketAddress listen = cci == null || cci.getWebListen() == null
|
||||||
}else {
|
? new MultiProtocolSocketAddress("http", "0.0.0.0", 4665) : cci.getWebListen();
|
||||||
throw new IllegalStateException("Remote Management already enabled!");
|
enableWebServer(listen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enableWebServer(int port) throws IOException {
|
||||||
|
enableWebServer(new MultiProtocolSocketAddress("http", "0.0.0.0", port));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enableWebServer(MultiProtocolSocketAddress listen) throws IOException {
|
||||||
|
if (webServer == null) {
|
||||||
|
webServer = new KLALBWebServer(this, listen);
|
||||||
|
webServer.start();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Web server already enabled!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enableRemoteManagement(MultiProtocolSocketAddress bind) throws IOException {
|
public boolean isWebServerEnabled() {
|
||||||
if(krm==null) {
|
return webServer != null && webServer.isRunning();
|
||||||
krm=new KLALBRemoteManagement(this,bind);
|
|
||||||
}else {
|
|
||||||
throw new IllegalStateException("Remote Management already enabled!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRemoteManagementEnabled() {
|
public KLALBWebServer getWebServer() {
|
||||||
return krm!=null;
|
return webServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableRemoteManagement() {
|
public void disableWebServer() {
|
||||||
if(krm!=null) {
|
if (webServer != null) {
|
||||||
krm.close();
|
webServer.stop();
|
||||||
krm=null;
|
webServer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,9 +168,11 @@ public class KLALBProxySystem {
|
|||||||
|
|
||||||
|
|
||||||
String vsne=kcci.getVirtualSocketName();
|
String vsne=kcci.getVirtualSocketName();
|
||||||
//if(vsne!=null) {
|
if(vsne!=null) {
|
||||||
MultiProtocolSocketAddress.getSocketTypeRegister().put(vsne, klalbController.getStreamSocketType());
|
MultiProtocolSocketAddress.getSocketTypeRegister().put(vsne, klalbController.getStreamSocketType());
|
||||||
//}
|
}else{
|
||||||
|
MultiProtocolSocketAddress.getSocketTypeRegister().put(CONST.KLTP_VIRTUAL_SOCKET_NAME, klalbController.getStreamSocketType());
|
||||||
|
}
|
||||||
MultiProtocolSocketAddress tcple=kcci.getTCPListen();
|
MultiProtocolSocketAddress tcple=kcci.getTCPListen();
|
||||||
if(tcple!=null) {
|
if(tcple!=null) {
|
||||||
|
|
||||||
@@ -195,30 +234,24 @@ public class KLALBProxySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void saveConfigToFile() {
|
||||||
|
if (jsonFile != null && config != null) {
|
||||||
|
String json = gson.toJson(config);
|
||||||
|
try (FileWriter fw = new FileWriter(jsonFile)) {
|
||||||
|
fw.write(json);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private KLALBStateGUI3 kgui;
|
private KLALBStateGUI3 kgui;
|
||||||
public KLALBStateGUI3 getKLALBGUI() {
|
public KLALBStateGUI3 getKLALBGUI() {
|
||||||
if(kgui==null) {
|
if(kgui==null) {
|
||||||
kgui=new KLALBStateGUI3(klalbController);
|
kgui=new KLALBStateGUI3(klalbController);
|
||||||
kgui.loadConfig(config);
|
kgui.loadConfig(config);
|
||||||
kgui.setSaveComsumer((cfg)->{
|
kgui.setSaveComsumer((cfg)->{
|
||||||
String json=gson.toJson(cfg);
|
saveConfigToFile();
|
||||||
if(jsonFile!=null) {
|
|
||||||
FileWriter fw = null;
|
|
||||||
try {
|
|
||||||
fw=new FileWriter(jsonFile);
|
|
||||||
fw.write(json);
|
|
||||||
}catch(IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}finally {
|
|
||||||
if(fw!=null)
|
|
||||||
try {
|
|
||||||
fw.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return kgui;
|
return kgui;
|
||||||
|
|||||||
@@ -13,13 +13,15 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.Condition;
|
import java.util.concurrent.locks.Condition;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.LockSupport;
|
import java.util.concurrent.locks.LockSupport;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.jctools.queues.MpscArrayQueue;
|
import org.jctools.queues.varhandle.MpscVarHandleArrayQueue;
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
import org.kne.cloud.clock.NTPTimestamps;
|
import org.kne.cloud.clock.NTPTimestamps;
|
||||||
import org.kne.cloud.clock.ReliabilityBackoffTimeClock;
|
import org.kne.cloud.clock.ReliabilityBackoffTimeClock;
|
||||||
@@ -31,17 +33,8 @@ import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
|||||||
import org.kne.cloud.network.congestion.CongestionAlgorithms;
|
import org.kne.cloud.network.congestion.CongestionAlgorithms;
|
||||||
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
||||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||||
import org.kne.cloud.network.ipv6.ControlledIPv6NetworkLink;
|
import org.kne.cloud.network.ipv6.*;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
|
||||||
import org.kne.cloud.network.ipv6.IPv6HopByHopTLV;
|
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6HopByHopHeader;
|
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6HopByHopHeader;
|
||||||
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
|
||||||
import org.kne.cloud.network.ipv6.KLALBOAMHopByHopTLV;
|
|
||||||
import org.kne.cloud.network.ipv6.KLALBPassportHopByHopTLV;
|
|
||||||
import org.kne.cloud.network.ipv6.Neighbor;
|
|
||||||
import org.kne.cloud.network.ipv6.PostcardEntry;
|
|
||||||
import org.kne.cloud.network.ipv6.RouteItem;
|
|
||||||
import org.kne.cloud.network.monitor.CostSupplierFactory;
|
import org.kne.cloud.network.monitor.CostSupplierFactory;
|
||||||
import org.kne.cloud.network.monitor.DelayMonitorData;
|
import org.kne.cloud.network.monitor.DelayMonitorData;
|
||||||
import org.kne.cloud.network.monitor.LinkStatus;
|
import org.kne.cloud.network.monitor.LinkStatus;
|
||||||
@@ -142,15 +135,18 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
}
|
}
|
||||||
|
|
||||||
public KLALBRemoteLink(KLALBController controller,KLALBPacketLink kpl, IPv6AddressGroup address) {
|
public KLALBRemoteLink(KLALBController controller,KLALBPacketLink kpl, IPv6AddressGroup address) {
|
||||||
|
super(false);
|
||||||
this.klalbController=controller;
|
this.klalbController=controller;
|
||||||
sysclk = klalbController.getClock();
|
sysclk = klalbController.getClock();
|
||||||
this.kplink = kpl;
|
this.kplink = kpl;
|
||||||
this.addressGroup = address;
|
this.addressGroup = address;
|
||||||
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||||
name=kpl.toString();
|
name=kpl.toString();
|
||||||
|
setCostSupplier( CostSupplierFactory.owdSupplier(monitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
private KLALBRemoteLink(KLALBController controller, MultiProtocolSocketAddress mpa, MultiProtocolSocketAddress bindaddr, IPv6AddressGroup address) {
|
private KLALBRemoteLink(KLALBController controller, MultiProtocolSocketAddress mpa, MultiProtocolSocketAddress bindaddr, IPv6AddressGroup address) {
|
||||||
|
super(false);
|
||||||
this.klalbController=controller;
|
this.klalbController=controller;
|
||||||
sysclk = klalbController.getClock();
|
sysclk = klalbController.getClock();
|
||||||
this.socketAddress = mpa;
|
this.socketAddress = mpa;
|
||||||
@@ -162,6 +158,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
} else {
|
} else {
|
||||||
name=bindaddr.toString() + "→" + mpa.toString();
|
name=bindaddr.toString() + "→" + mpa.toString();
|
||||||
}
|
}
|
||||||
|
setCostSupplier( CostSupplierFactory.owdSupplier( monitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -187,7 +184,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
|
|
||||||
private class RemoteSender implements Runnable {
|
private class RemoteSender implements Runnable {
|
||||||
|
|
||||||
private MpscArrayQueue<KLALBPacket> sendQueue = new MpscArrayQueue<KLALBPacket>(8192);
|
private MpscVarHandleArrayQueue<KLALBPacket> sendQueue = new MpscVarHandleArrayQueue<KLALBPacket>(8192);
|
||||||
private WatchDogTimer watchdog = new WatchDogTimer(400000000L);
|
private WatchDogTimer watchdog = new WatchDogTimer(400000000L);
|
||||||
|
|
||||||
private ThreadParker tlock = new ThreadParker();
|
private ThreadParker tlock = new ThreadParker();
|
||||||
@@ -281,12 +278,12 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
sendLock.lock();
|
sendLock.lock();
|
||||||
try {
|
try {
|
||||||
kplink.flush();
|
kplink.flush();
|
||||||
watchdog.feed();
|
|
||||||
}finally {
|
}finally {
|
||||||
sendLock.unlock();
|
sendLock.unlock();
|
||||||
}
|
}
|
||||||
|
watchdog.feed();
|
||||||
}
|
}
|
||||||
tlock.parkNanos(10000000L);
|
tlock.parkNanos(1000000L);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (StreamCorruptedException sce) {
|
} catch (StreamCorruptedException sce) {
|
||||||
@@ -566,20 +563,17 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
private ThreadParker tpk=new ThreadParker();
|
private ThreadParker tpk=new ThreadParker();
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateManager stateManager;
|
||||||
private MonitorUpdater monitorUpdater;
|
private ScheduledFuture<?> monitorUpdater;
|
||||||
private class MonitorUpdater implements Runnable{
|
private class MonitorUpdater implements Runnable{
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!closed) {
|
if(closed) {
|
||||||
|
monitorUpdater.cancel(false);
|
||||||
|
}else{
|
||||||
status.updateReliability();
|
status.updateReliability();
|
||||||
if(status.getState()!=LinkStatus.DOWN) {
|
if(status.getState()!=LinkStatus.DOWN) {
|
||||||
monitor.update();
|
monitor.update();
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
Thread.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,8 +745,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
|
|
||||||
protected void startIO() {
|
protected void startIO() {
|
||||||
stateManager=new StateManager();
|
stateManager=new StateManager();
|
||||||
monitorUpdater=new MonitorUpdater();
|
monitorUpdater=KLALBScheduler.getScheduler().scheduleWithFixedDelay(new MonitorUpdater(),1,1, TimeUnit.MILLISECONDS);
|
||||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
|
||||||
ThreadTool.makeVDaemonThread("远程线路状态线程", stateManager).start();
|
ThreadTool.makeVDaemonThread("远程线路状态线程", stateManager).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -854,10 +847,6 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLoopBack() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
BandwidthDistributer bandwidthDistributer=new BandwidthDistributer<>();
|
BandwidthDistributer bandwidthDistributer=new BandwidthDistributer<>();
|
||||||
@Override
|
@Override
|
||||||
public List<Neighbor> getNeighborsInfo() {
|
public List<Neighbor> getNeighborsInfo() {
|
||||||
@@ -898,6 +887,8 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
sendWindow.put(val, pack);
|
sendWindow.put(val, pack);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
}else {
|
||||||
|
System.out.println(hop);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendIPv6PacketToLink(pack, val);
|
sendIPv6PacketToLink(pack, val);
|
||||||
@@ -946,31 +937,6 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
return (!isClosed()) && (status.getState() == LinkStatus.UP) ;
|
return (!isClosed()) && (status.getState() == LinkStatus.UP) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RouteItem> getRouteItems() {
|
|
||||||
List<RouteItem> rlist = new ArrayList<>();
|
|
||||||
|
|
||||||
if(isUp()) {
|
|
||||||
IPv6AddressGroup adg = addressGroup;
|
|
||||||
/*if (adg != null)
|
|
||||||
rlist.add(new RouteItem(new IPv6AddressGroup(adg.getAddress(), 128), adg.getAddress(), this, "Direct", 0, 0,
|
|
||||||
null, "D", true));*/
|
|
||||||
|
|
||||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext(); ) {
|
|
||||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
|
||||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
|
||||||
addresses.getAddress().getAddress(), this, "Direct", 0, 128, CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(), status, algorithm::getRTO), "D", false);
|
|
||||||
rlist.add(ri);
|
|
||||||
|
|
||||||
if (addresses.getLocator() != null) {
|
|
||||||
RouteItem ris = new RouteItem(addresses.getLocator(), addresses.getLocator().getAddress(), this,
|
|
||||||
"KLALB SRv6", 13, 128, CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(), status, algorithm::getRTO), "D", false);
|
|
||||||
rlist.add(ris);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCongressCondition(Lock lock, Condition condition) {
|
public void setCongressCondition(Lock lock, Condition condition) {
|
||||||
@@ -978,14 +944,32 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
|
|||||||
sendWindow.setCongressCondition(lock, condition);
|
sendWindow.setCongressCondition(lock, condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPostcardReceive(PostcardEntry postcard) {
|
public void onPostcardReceive(IPv6NetworkLink linkfrom,PostcardEntry postcard) {
|
||||||
long deltaxnanos = (long) (postcard.getTimestampDeltaLong() * 1000000000.0 / (1L << 32));
|
long deltaxnanos = (long) (postcard.getTimestampDeltaLong() * 1000000000.0 / (1L << 32));
|
||||||
if (deltaxnanos > 0) {
|
Long128 curr= sysclk.getCurrentTimeNanos();
|
||||||
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||||
NTPTimestamps.inferNtp64To128(postcard.getTimestampBase(), sysclk.getCurrentTimeNTP128()));
|
NTPTimestamps.inferNtp64To128(postcard.getTimestampBase(),NTPTimestamps.nanosToNtp128BitTimestamp(curr)));
|
||||||
|
long rtt=curr.subtract(psnd).longValue();
|
||||||
|
if (deltaxnanos >= 0) {
|
||||||
monitor.recordUploadDelay(deltaxnanos);
|
monitor.recordUploadDelay(deltaxnanos);
|
||||||
}
|
}
|
||||||
sendWindow.ack(postcard.getPacketUUID(),false,deltaxnanos);
|
if(linkfrom instanceof KLALBRemoteLink ){
|
||||||
|
long rtt2=deltaxnanos+((KLALBRemoteLink) linkfrom).getMonitor().getInDelayMin();
|
||||||
|
|
||||||
|
if(rtt2<0) {
|
||||||
|
if(rtt<0) {
|
||||||
|
rtt=0;
|
||||||
|
}
|
||||||
|
sendWindow.ack(postcard.getPacketUUID(), rtt, false);
|
||||||
|
}else {
|
||||||
|
sendWindow.ack(postcard.getPacketUUID(), rtt2, false);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(rtt<0) {
|
||||||
|
rtt=0;
|
||||||
|
}
|
||||||
|
sendWindow.ack(postcard.getPacketUUID(), rtt, false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
package org.kne.cloud.network.klalb;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
|
||||||
import org.kne.cloud.network.SocketListener;
|
|
||||||
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
|
|
||||||
import org.kne.cloud.network.monitor.LinkStatus;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
|
|
||||||
public class KLALBRemoteManagement {
|
|
||||||
SocketListener slr;
|
|
||||||
private KLALBProxySystem klalbProxySystem;
|
|
||||||
public KLALBRemoteManagement(KLALBProxySystem klalbProxySystem) throws IOException {
|
|
||||||
this(klalbProxySystem,new MultiProtocolSocketAddress("127.9.9.9", 49573));
|
|
||||||
}
|
|
||||||
public KLALBRemoteManagement(KLALBProxySystem klalbProxySystem, MultiProtocolSocketAddress listen) throws IOException {
|
|
||||||
this.klalbProxySystem=klalbProxySystem;
|
|
||||||
slr=new SocketListener(listen);
|
|
||||||
slr.setCon((srcv)->{
|
|
||||||
try {
|
|
||||||
srcv.setSoTimeout(10000);
|
|
||||||
byte[]input= srcv.getInputStream().readAllBytes();
|
|
||||||
srcv.shutdownInput();
|
|
||||||
String req=new String(input,Charset.forName("UTF-8"));
|
|
||||||
System.out.println("远程管理请求:"+req);
|
|
||||||
String rsp=processSignal(req);
|
|
||||||
System.out.println("远程管理响应:"+rsp);
|
|
||||||
srcv.getOutputStream().write(rsp.getBytes(Charset.forName("UTF-8")));
|
|
||||||
srcv.shutdownOutput();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}finally {
|
|
||||||
try {
|
|
||||||
srcv.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public KLALBProxySystem getKlalbProxySystem() {
|
|
||||||
return klalbProxySystem;
|
|
||||||
}
|
|
||||||
private String processSignal(String req) {
|
|
||||||
JsonObject jreq= (JsonObject) new JsonParser().parse(req);
|
|
||||||
JsonObject jrsp=new JsonObject();
|
|
||||||
|
|
||||||
|
|
||||||
String reqt=jreq.getAsJsonPrimitive("REQ").getAsString();
|
|
||||||
jrsp.addProperty("RSP", reqt);
|
|
||||||
switch (reqt) {
|
|
||||||
case "GETLINES":
|
|
||||||
JsonArray lines=new JsonArray();
|
|
||||||
List<IPv6NetworkLink>lineslist= klalbProxySystem.getKlalbController().getLines();
|
|
||||||
synchronized (lineslist) {
|
|
||||||
for (Iterator<IPv6NetworkLink> iterator = lineslist.iterator(); iterator.hasNext();) {
|
|
||||||
IPv6NetworkLink link=iterator.next();
|
|
||||||
if(!(link instanceof KLALBRemoteLink)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) link;
|
|
||||||
if(klalbRemoteLine.getSocketAddress()==null)
|
|
||||||
continue;
|
|
||||||
JsonObject jklbrl=new JsonObject();
|
|
||||||
jklbrl.addProperty("ipport", klalbRemoteLine.getSocketAddress().toString());
|
|
||||||
jklbrl.addProperty("state",LinkStatus.stateToString( klalbRemoteLine.getState()));
|
|
||||||
|
|
||||||
jklbrl.addProperty("Vaddr", klalbRemoteLine.getRemoteVaddr().getAddress().toString());
|
|
||||||
|
|
||||||
jklbrl.addProperty("uploadspeed", klalbRemoteLine.getMonitor().getOutSpeed());
|
|
||||||
jklbrl.addProperty("downloadspeed", klalbRemoteLine.getMonitor().getInSpeed());
|
|
||||||
|
|
||||||
jklbrl.addProperty("uploadtraffic", klalbRemoteLine.getMonitor().getOutTraffic());
|
|
||||||
jklbrl.addProperty("downloadtraffic", klalbRemoteLine.getMonitor().getInTraffic());
|
|
||||||
|
|
||||||
jklbrl.addProperty("uploaddelay",klalbRemoteLine.getMonitor().getOutDelay() );
|
|
||||||
jklbrl.addProperty("downloaddelay", klalbRemoteLine.getMonitor().getInDelay());
|
|
||||||
|
|
||||||
jklbrl.addProperty("uploaddelaymin",klalbRemoteLine.getMonitor().getOutDelayMin() );
|
|
||||||
jklbrl.addProperty("downloaddelaymin", klalbRemoteLine.getMonitor().getInDelayMin());
|
|
||||||
lines.add(jklbrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jrsp.add("table", lines);
|
|
||||||
break;
|
|
||||||
case "ADDLINE":
|
|
||||||
String mip=jreq.getAsJsonPrimitive("ipport").getAsString();
|
|
||||||
try {
|
|
||||||
|
|
||||||
jrsp.addProperty ("Vaddr",klalbProxySystem.getKlalbController().getRemoteVaddrBySocketAddress(new MultiProtocolSocketAddress(mip)).getHostAddress());
|
|
||||||
} catch (SocketTimeoutException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GETSELFLINES":
|
|
||||||
JsonArray lines2=new JsonArray();
|
|
||||||
List<MultiProtocolSocketAddress>selflineslist=klalbProxySystem.getKlalbController().getSelflineTable();
|
|
||||||
synchronized (selflineslist) {
|
|
||||||
for (Iterator<MultiProtocolSocketAddress> iterator = selflineslist.iterator(); iterator.hasNext();) {
|
|
||||||
MultiProtocolSocketAddress multiProtocolSocketAddress = (MultiProtocolSocketAddress) iterator.next();
|
|
||||||
lines2.add(new JsonPrimitive(multiProtocolSocketAddress.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jrsp.add("table", lines2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "ADDSELFLINE":
|
|
||||||
String mips=jreq.getAsJsonPrimitive("ipport").getAsString();
|
|
||||||
List<MultiProtocolSocketAddress>selflineslist2=klalbProxySystem.getKlalbController().getSelflineTable();
|
|
||||||
synchronized (selflineslist2) {
|
|
||||||
selflineslist2.add(new MultiProtocolSocketAddress(mips));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "REMOVESELFLINE":
|
|
||||||
String mipsr=jreq.getAsJsonPrimitive("ipport").getAsString();
|
|
||||||
List<MultiProtocolSocketAddress>selflineslist21=klalbProxySystem.getKlalbController().getSelflineTable();
|
|
||||||
synchronized (selflineslist21) {
|
|
||||||
selflineslist21.add(new MultiProtocolSocketAddress(mipsr));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GETLINKMONITOR":
|
|
||||||
jrsp.addProperty("uploadspeed", klalbProxySystem.getKlalbController().getLinkMonitor().getOutSpeed());
|
|
||||||
jrsp.addProperty("downloadspeed", klalbProxySystem.getKlalbController().getLinkMonitor().getInSpeed());
|
|
||||||
|
|
||||||
jrsp.addProperty("uploadtraffic", klalbProxySystem.getKlalbController().getLinkMonitor().getOutTraffic());
|
|
||||||
jrsp.addProperty("downloadtraffic", klalbProxySystem.getKlalbController().getLinkMonitor().getInTraffic());
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "OPENMONITORUI":
|
|
||||||
klalbProxySystem.getKLALBGUI().setVisible(true);
|
|
||||||
break;
|
|
||||||
/*case "GETSOCKETBRIDGE":
|
|
||||||
JsonArray bridges=new JsonArray();
|
|
||||||
Set<Proxy> pxy=klalbProxySystem.getProxys();
|
|
||||||
synchronized (pxy) {
|
|
||||||
for (Iterator<Proxy> iterator = pxy.iterator(); iterator.hasNext();) {
|
|
||||||
Proxy proxy = (Proxy) iterator.next();
|
|
||||||
bridges.add(klalbProxySystem.createJsonObjectByProxy(proxy));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jrsp.add("table", bridges);
|
|
||||||
break;
|
|
||||||
case "ADDSOCKETBRIDGE":
|
|
||||||
JsonObject jpxy= jreq.getAsJsonObject("socketbridge");
|
|
||||||
Set<Proxy> pxy2=klalbProxySystem.getProxys();
|
|
||||||
synchronized (pxy2) {
|
|
||||||
try {
|
|
||||||
pxy2.add(klalbProxySystem.createProxyByJson(jpxy));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;*/
|
|
||||||
default:
|
|
||||||
System.out.println("未知请求类型:"+reqt);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return jrsp.toString();
|
|
||||||
}
|
|
||||||
public void close() {
|
|
||||||
slr.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.kne.cloud.network.klalb;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
public class KLALBScheduler {
|
||||||
|
private static final ScheduledExecutorService scheduler;
|
||||||
|
static {
|
||||||
|
scheduler= Executors.newScheduledThreadPool( Runtime.getRuntime().availableProcessors(),
|
||||||
|
(r) -> {
|
||||||
|
Thread t = new Thread(r, "KLALB-Scheduler");
|
||||||
|
t.setDaemon(true); // 守护线程,不阻止 JVM 退出
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static ScheduledExecutorService getScheduler(){
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,8 +13,6 @@ import java.util.UUID;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.jctools.counters.CountersFactory;
|
|
||||||
import org.jctools.counters.FixedSizeStripedLongCounter;
|
|
||||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||||
|
|
||||||
@@ -434,7 +432,5 @@ public static String parseAbbrIPv6(String IPv6Str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static FixedSizeStripedLongCounter createCounter() {
|
|
||||||
return CountersFactory.createFixedSizeStripedCounter(Runtime.getRuntime().availableProcessors());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import java.net.SocketException;
|
|||||||
|
|
||||||
import org.kne.cloud.network.VirtualDatagramSocket;
|
import org.kne.cloud.network.VirtualDatagramSocket;
|
||||||
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
import org.kne.cloud.network.VirtualDatagramSocketImpl;
|
||||||
import org.pcap4j.core.Inets;
|
|
||||||
|
|
||||||
public class KLALBVirtualDatagramSocket extends VirtualDatagramSocket {
|
public class KLALBVirtualDatagramSocket extends VirtualDatagramSocket {
|
||||||
|
|
||||||
|
|||||||
@@ -118,46 +118,50 @@ public class StreamChannelKLALBPacketLink extends AbstractKLALBPacketLink implem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 增加两个 ThreadLocal 静态变量,用于复用 4 字节的长度头
|
||||||
|
private static final ThreadLocal<ByteBuffer> SIZE_WRITE_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(4));
|
||||||
|
private static final ThreadLocal<ByteBuffer> SIZE_READ_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(4));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writePacket(ByteBuffer kp) throws IOException {
|
public void writePacket(ByteBuffer kp) throws IOException {
|
||||||
ByteBuffer szeWrite=NetworkPacket.bufferAllocator.allocate(4);
|
// 1. 获取并清空缓存的 4 字节 buffer
|
||||||
szeWrite.limit(4);
|
ByteBuffer szeWrite = SIZE_WRITE_BUFFER.get();
|
||||||
//szeWrite.clear();
|
szeWrite.clear();
|
||||||
|
|
||||||
|
// 2. 写入长度并翻转
|
||||||
szeWrite.putInt(kp.limit());
|
szeWrite.putInt(kp.limit());
|
||||||
szeWrite.flip();
|
szeWrite.flip();
|
||||||
KLALBVirtualSocketChannel obj = null;
|
|
||||||
writableChannel.write(new ByteBuffer[] {szeWrite,kp});
|
// 3. 发送
|
||||||
|
writableChannel.write(new ByteBuffer[] {szeWrite, kp});
|
||||||
checkflush();
|
checkflush();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer readPacket() throws IOException {
|
public ByteBuffer readPacket() throws IOException {
|
||||||
|
// 1. 获取并清空缓存的 4 字节 buffer
|
||||||
ByteBuffer szeRead=NetworkPacket.bufferAllocator.allocate(4);
|
ByteBuffer szeRead = SIZE_READ_BUFFER.get();
|
||||||
timeoutTimer=System.nanoTime();
|
|
||||||
timerenabled=true;
|
|
||||||
ByteBuffer kp;
|
|
||||||
szeRead.clear();
|
szeRead.clear();
|
||||||
szeRead.limit(4);
|
szeRead.limit(4);
|
||||||
//szeRead.clear();
|
|
||||||
|
timeoutTimer = System.nanoTime();
|
||||||
|
timerenabled = true;
|
||||||
|
ByteBuffer kp;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
KNEChannels.readFully(readableChannel,szeRead);
|
// 2. 读取长度头
|
||||||
|
KNEChannels.readFully(readableChannel, szeRead);
|
||||||
szeRead.flip();
|
szeRead.flip();
|
||||||
int size=szeRead.getInt(0);
|
int size = szeRead.getInt(0);
|
||||||
kp=NetworkPacket.bufferAllocator.allocate(size);
|
|
||||||
|
// 3. 分配真正的数据区(这里如果是高频,建议后续也可以池化,不过现在是按需大小分配)
|
||||||
|
kp = NetworkPacket.bufferAllocator.allocate(size);
|
||||||
kp.limit(size);
|
kp.limit(size);
|
||||||
KNEChannels.readFully(readableChannel, kp);
|
KNEChannels.readFully(readableChannel, kp);
|
||||||
kp.flip();
|
kp.flip();
|
||||||
return kp;
|
return kp;
|
||||||
}finally {
|
} finally {
|
||||||
timerenabled=false;
|
timerenabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import java.awt.*;
|
|||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
@@ -16,6 +17,7 @@ import javax.swing.border.LineBorder;
|
|||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
|
import com.sun.management.OperatingSystemMXBean;
|
||||||
import org.jfree.chart.plot.dial.*;
|
import org.jfree.chart.plot.dial.*;
|
||||||
import org.jfree.data.general.DefaultValueDataset;
|
import org.jfree.data.general.DefaultValueDataset;
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
@@ -37,8 +39,7 @@ import org.kne.ui.YScrollPane;
|
|||||||
public class KLALBStateGUI3 extends XFrame {
|
public class KLALBStateGUI3 extends XFrame {
|
||||||
|
|
||||||
// ==================== 定时任务相关 ====================
|
// ==================== 定时任务相关 ====================
|
||||||
private TimerTask tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
|
private ScheduledFuture<?> tsk, tsk2, tsk3, tsk4, tsk5; // 各种定时任务
|
||||||
private Timer t, t2, t3; // 定时器
|
|
||||||
|
|
||||||
// ==================== 系统托盘相关 ====================
|
// ==================== 系统托盘相关 ====================
|
||||||
private SystemTray st; // 系统托盘
|
private SystemTray st; // 系统托盘
|
||||||
@@ -57,7 +58,8 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private DefaultValueDataset backplanePPS;
|
private DefaultValueDataset backplanePPS;
|
||||||
private DefaultValueDataset backplaneECNRate;
|
private DefaultValueDataset backplaneECNRate;
|
||||||
private DefaultValueDataset backplaneLossRate;
|
private DefaultValueDataset backplaneLossRate;
|
||||||
|
private DefaultValueDataset CPUload;
|
||||||
|
private DefaultValueDataset RAMusage;
|
||||||
// ==================== 仪表盘文本标注 ====================
|
// ==================== 仪表盘文本标注 ====================
|
||||||
private DialTextAnnotation upSpeedText; // 上行速度文本标注
|
private DialTextAnnotation upSpeedText; // 上行速度文本标注
|
||||||
private DialTextAnnotation downSpeedText; // 下行速度文本标注
|
private DialTextAnnotation downSpeedText; // 下行速度文本标注
|
||||||
@@ -67,6 +69,8 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private DialTextAnnotation backplanePPSText;
|
private DialTextAnnotation backplanePPSText;
|
||||||
private DialTextAnnotation backplaneECNRateText;
|
private DialTextAnnotation backplaneECNRateText;
|
||||||
private DialTextAnnotation backplaneLossRateText;
|
private DialTextAnnotation backplaneLossRateText;
|
||||||
|
private DialTextAnnotation CPUloadText;
|
||||||
|
private DialTextAnnotation RAMusageText;
|
||||||
|
|
||||||
// ==================== UI组件 ====================
|
// ==================== UI组件 ====================
|
||||||
private YScrollPane ysp, yspc; // 可垂直滚动的面板
|
private YScrollPane ysp, yspc; // 可垂直滚动的面板
|
||||||
@@ -75,7 +79,9 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private JTextField addressField; // 地址显示框
|
private JTextField addressField; // 地址显示框
|
||||||
private JTextField addressFieldSet; // 地址设置框
|
private JTextField addressFieldSet; // 地址设置框
|
||||||
private JTextField asnFieldSet; // ASN设置框
|
private JTextField asnFieldSet; // ASN设置框
|
||||||
|
private JCheckBox enableTUN; // 虚拟网卡启用禁用
|
||||||
private JTextField tunDeviceName; // 虚拟网卡名称设置框
|
private JTextField tunDeviceName; // 虚拟网卡名称设置框
|
||||||
|
private JTextField webListenSet; // Web API 监听地址设置框
|
||||||
private NetworkGraphPanel graph; // 网络图面板
|
private NetworkGraphPanel graph; // 网络图面板
|
||||||
private JTextField textFieldLocate; // 定位地址输入框
|
private JTextField textFieldLocate; // 定位地址输入框
|
||||||
private JTextField asnField2; // ASN显示框
|
private JTextField asnField2; // ASN显示框
|
||||||
@@ -96,6 +102,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private JTextArea ntpServerSet; // NTP服务器设置区域
|
private JTextArea ntpServerSet; // NTP服务器设置区域
|
||||||
private JCheckBox denyBroadcast;
|
private JCheckBox denyBroadcast;
|
||||||
private JCheckBox denyQuery;
|
private JCheckBox denyQuery;
|
||||||
|
private JCheckBox webApiEnabled; // 启用 Web API 开关
|
||||||
private ClosableTabbedPane tabbedPane; // 可关闭的标签页面板
|
private ClosableTabbedPane tabbedPane; // 可关闭的标签页面板
|
||||||
private JCheckBox nogui;
|
private JCheckBox nogui;
|
||||||
|
|
||||||
@@ -431,6 +438,22 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
backplaneLossRateText = lossRate1.getTextAnnotation();
|
backplaneLossRateText = lossRate1.getTextAnnotation();
|
||||||
|
|
||||||
dashs.add(lossRate1);
|
dashs.add(lossRate1);
|
||||||
|
|
||||||
|
// CPU
|
||||||
|
CPUload = new DefaultValueDataset(0);
|
||||||
|
DialPanel cload=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("cpuload"), CPUload, null, Color.BLUE, new Color(0, 0, 127));
|
||||||
|
cload.addGradientRanges(UIEnv.RANGE_1);
|
||||||
|
CPUloadText = cload.getTextAnnotation();
|
||||||
|
|
||||||
|
dashs.add(cload);
|
||||||
|
|
||||||
|
// RAM
|
||||||
|
RAMusage = new DefaultValueDataset(0);
|
||||||
|
DialPanel ruse=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("ramusage"), RAMusage, null, Color.BLUE, new Color(0, 0, 127));
|
||||||
|
ruse.addGradientRanges(UIEnv.RANGE_1);
|
||||||
|
RAMusageText = ruse.getTextAnnotation();
|
||||||
|
|
||||||
|
dashs.add(ruse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -702,10 +725,6 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
* 初始化定时器
|
* 初始化定时器
|
||||||
*/
|
*/
|
||||||
private void initTimers(KLALBController kc) {
|
private void initTimers(KLALBController kc) {
|
||||||
t3 = new Timer("监视器刷新线程", true);
|
|
||||||
t2 = new Timer("仪表盘刷新线程", true);
|
|
||||||
t = new Timer("状态刷新线程", true);
|
|
||||||
|
|
||||||
// 创建刷新任务
|
// 创建刷新任务
|
||||||
createRefreshTask(kc, ysp);
|
createRefreshTask(kc, ysp);
|
||||||
}
|
}
|
||||||
@@ -820,6 +839,12 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
asnFieldSet = asn.getTextField();
|
asnFieldSet = asn.getTextField();
|
||||||
settings.getView().add(asn);
|
settings.getView().add(asn);
|
||||||
|
|
||||||
|
//虚拟网卡
|
||||||
|
CheckBoxSettingItem enableTUNs = new CheckBoxSettingItem(UIEnv.getRsb().getString("enabletun"),
|
||||||
|
CONST.itemwidth, CONST.settingheight);
|
||||||
|
enableTUN=enableTUNs.getCheckBox();
|
||||||
|
settings.getView().add(enableTUNs);
|
||||||
|
|
||||||
TextSettingItem tunName = new TextSettingItem(UIEnv.getRsb().getString("tunname"),
|
TextSettingItem tunName = new TextSettingItem(UIEnv.getRsb().getString("tunname"),
|
||||||
CONST.itemwidth, CONST.settingheight);
|
CONST.itemwidth, CONST.settingheight);
|
||||||
tunDeviceName = tunName.getTextField();
|
tunDeviceName = tunName.getTextField();
|
||||||
@@ -905,6 +930,21 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
denyBroadcast=denyBroadcastc.getCheckBox();
|
denyBroadcast=denyBroadcastc.getCheckBox();
|
||||||
settings.getView().add(denyBroadcastc);
|
settings.getView().add(denyBroadcastc);
|
||||||
|
|
||||||
|
// Web服务设置标题
|
||||||
|
SettingItem wsi = new SettingItem(UIEnv.getRsb().getString("webapisettings"),
|
||||||
|
UIEnv.getFont().deriveFont(20.0f).deriveFont(Font.BOLD), CONST.itemwidth, CONST.settingheight);
|
||||||
|
settings.getView().add(wsi);
|
||||||
|
|
||||||
|
CheckBoxSettingItem webApic = new CheckBoxSettingItem(UIEnv.getRsb().getString("enablewebapi"),
|
||||||
|
CONST.itemwidth, CONST.settingheight);
|
||||||
|
webApiEnabled=webApic.getCheckBox();
|
||||||
|
settings.getView().add(webApic);
|
||||||
|
|
||||||
|
TextSettingItem webListen = new TextSettingItem(UIEnv.getRsb().getString("weblistenaddr"),
|
||||||
|
CONST.itemwidth, CONST.settingheight);
|
||||||
|
webListenSet = webListen.getTextField();
|
||||||
|
settings.getView().add(webListen);
|
||||||
|
|
||||||
//性能设置标题
|
//性能设置标题
|
||||||
|
|
||||||
SettingItem pshi = new SettingItem(UIEnv.getRsb().getString("performancesettings"),
|
SettingItem pshi = new SettingItem(UIEnv.getRsb().getString("performancesettings"),
|
||||||
@@ -1134,6 +1174,8 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kck.setEnableTUN( enableTUN.isSelected());
|
||||||
|
|
||||||
String tunNameText=tunDeviceName.getText().trim();
|
String tunNameText=tunDeviceName.getText().trim();
|
||||||
if(tunNameText.equals("") || tunNameText.equalsIgnoreCase("null")) {
|
if(tunNameText.equals("") || tunNameText.equalsIgnoreCase("null")) {
|
||||||
kck.setTUNName(null);
|
kck.setTUNName(null);
|
||||||
@@ -1141,6 +1183,22 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
kck.setTUNName(tunNameText);
|
kck.setTUNName(tunNameText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存Web API设置
|
||||||
|
kck.setWebUI(webApiEnabled.isSelected());
|
||||||
|
String webListenText = webListenSet.getText().trim();
|
||||||
|
if (webListenText.equals("")) {
|
||||||
|
kck.setWebListen(new MultiProtocolSocketAddress("http", "0.0.0.0", 4665));
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
kck.setWebListen(new MultiProtocolSocketAddress(webListenText));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildweblistenaddr"),
|
||||||
|
UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 保存TCP监听设置
|
// 保存TCP监听设置
|
||||||
String tcptext = tcpListeningSet.getText();
|
String tcptext = tcpListeningSet.getText();
|
||||||
if (tcptext.equals("")) {
|
if (tcptext.equals("")) {
|
||||||
@@ -1190,7 +1248,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kck.setLineTable(iaddr1);
|
kck.setExternalEndpoints(iaddr1);
|
||||||
|
|
||||||
// 保存自动连接线路表
|
// 保存自动连接线路表
|
||||||
String[] splt11 = connectLineTabelSet.getText().split("\n");
|
String[] splt11 = connectLineTabelSet.getText().split("\n");
|
||||||
@@ -1243,9 +1301,9 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
|
|
||||||
kck.setLinkConnectionsCount(linkConnectionsCount.getSlider().getValue());
|
kck.setLinkConnectionsCount(linkConnectionsCount.getSlider().getValue());
|
||||||
|
|
||||||
kck.setDenyLineTableQuery(denyQuery.isSelected());
|
kck.setDenyExternalEndpointQuery(denyQuery.isSelected());
|
||||||
|
|
||||||
kck.setDenyLineTableBroadcast(denyBroadcast.isSelected());
|
kck.setDenyExternalEndpointBroadcast(denyBroadcast.isSelected());
|
||||||
|
|
||||||
PerformanceStrategyItem psi=((PerformanceStrategyItem)comboPerformance.getSelectedItem());
|
PerformanceStrategyItem psi=((PerformanceStrategyItem)comboPerformance.getSelectedItem());
|
||||||
if(psi!=null) {
|
if(psi!=null) {
|
||||||
@@ -1280,9 +1338,9 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private void createRefreshTask(KLALBController kc, YScrollPane ysp) {
|
private void createRefreshTask(KLALBController kc, YScrollPane ysp) {
|
||||||
// 线路状态刷新任务
|
// 线路状态刷新任务
|
||||||
if (tsk != null) {
|
if (tsk != null) {
|
||||||
tsk.cancel();
|
tsk.cancel(false);
|
||||||
}
|
}
|
||||||
tsk = new TimerTask() {
|
tsk =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
@@ -1340,28 +1398,27 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
ysp.updateScrool();
|
ysp.updateScrool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 1000, 1000, TimeUnit.MILLISECONDS);
|
||||||
t.scheduleAtFixedRate(tsk, 1000, 1000);
|
|
||||||
|
|
||||||
// 仪表盘数据刷新任务
|
// 仪表盘数据刷新任务
|
||||||
if (tsk2 != null) {
|
if (tsk2 != null) {
|
||||||
tsk2.cancel();
|
tsk2.cancel(false);
|
||||||
}
|
}
|
||||||
tsk2 = new TimerTask() {
|
tsk2 =KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
updateDashboardData(kc);
|
updateDashboardData(kc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 100, 100,TimeUnit.MILLISECONDS);
|
||||||
t2.scheduleAtFixedRate(tsk2, 100, 100);
|
|
||||||
|
|
||||||
// 网络图刷新任务
|
// 网络图刷新任务
|
||||||
if (tsk5 != null) {
|
if (tsk5 != null) {
|
||||||
tsk5.cancel();
|
tsk5.cancel(false);
|
||||||
}
|
}
|
||||||
tsk5 = new TimerTask() {
|
tsk5 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
@@ -1373,8 +1430,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
graph.revalidate();
|
graph.revalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 1000, 1000,TimeUnit.MILLISECONDS);
|
||||||
t.scheduleAtFixedRate(tsk5, 1000, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1383,29 +1439,29 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
private void updateDashboardData(KLALBController kc) {
|
private void updateDashboardData(KLALBController kc) {
|
||||||
// 更新上行速度
|
// 更新上行速度
|
||||||
double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
|
double outload = kc.getLinkMonitor().getOutSpeed() * 100.0 / kc.getLinkMonitor().getOutSpeedMax();
|
||||||
|
upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s");
|
||||||
if (Double.isFinite(outload)) {
|
if (Double.isFinite(outload)) {
|
||||||
upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s");
|
|
||||||
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新下行速度
|
// 更新下行速度
|
||||||
double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
|
double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
|
||||||
|
downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
|
||||||
if (Double.isFinite(inload)) {
|
if (Double.isFinite(inload)) {
|
||||||
downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
|
|
||||||
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新上行包速率
|
// 更新上行包速率
|
||||||
double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
|
double outPPSload = kc.getLinkMonitor().getOutPPS() * 100.0 / kc.getLinkMonitor().getOutPPSMax();
|
||||||
|
upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
|
||||||
if (Double.isFinite(outPPSload)) {
|
if (Double.isFinite(outPPSload)) {
|
||||||
upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
|
|
||||||
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新下行包速率
|
// 更新下行包速率
|
||||||
double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
|
double inPPSload = kc.getLinkMonitor().getInPPS() * 100.0 / kc.getLinkMonitor().getInPPSMax();
|
||||||
|
downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
|
||||||
if (Double.isFinite(inPPSload)) {
|
if (Double.isFinite(inPPSload)) {
|
||||||
downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
|
|
||||||
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1437,33 +1493,54 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
if(router!=null) {
|
if(router!=null) {
|
||||||
// 更新背板延迟
|
// 更新背板延迟
|
||||||
double backplaneTimev = router.getBackplaneTime()* 100.0/100000.0;
|
double backplaneTimev = router.getBackplaneTime()* 100.0/100000.0;
|
||||||
|
backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
|
||||||
if (Double.isFinite(backplaneTimev)) {
|
if (Double.isFinite(backplaneTimev)) {
|
||||||
backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
|
|
||||||
backplaneDelay.setValue(Math.min(backplaneDelay.getValue().doubleValue() * 0.98 + backplaneTimev * 0.02, 101.0));
|
backplaneDelay.setValue(Math.min(backplaneDelay.getValue().doubleValue() * 0.98 + backplaneTimev * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新背板转发率
|
// 更新背板转发率
|
||||||
double backplanePPSv = router.getBackplanePPS() * 100.0 / router.getBackplanePPSMax();
|
double backplanePPSv = router.getBackplanePPS() * 100.0 / router.getBackplanePPSMax();
|
||||||
|
backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
|
||||||
if (Double.isFinite(backplanePPSv)) {
|
if (Double.isFinite(backplanePPSv)) {
|
||||||
backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
|
|
||||||
backplanePPS.setValue(Math.min(backplanePPS.getValue().doubleValue() * 0.98 + backplanePPSv * 0.02, 101.0));
|
backplanePPS.setValue(Math.min(backplanePPS.getValue().doubleValue() * 0.98 + backplanePPSv * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新背板ECN率
|
// 更新背板ECN率
|
||||||
double backplaneECNv = router.getECNRate() * 100.0 ;
|
double backplaneECNv = router.getECNRate() * 100.0 ;
|
||||||
|
backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
|
||||||
if (Double.isFinite(backplaneECNv)) {
|
if (Double.isFinite(backplaneECNv)) {
|
||||||
backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
|
|
||||||
backplaneECNRate.setValue(Math.min(backplaneECNRate.getValue().doubleValue() * 0.98 + backplaneECNv * 0.02, 101.0));
|
backplaneECNRate.setValue(Math.min(backplaneECNRate.getValue().doubleValue() * 0.98 + backplaneECNv * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新背板ECN率
|
// 更新背板ECN率
|
||||||
double backplaneLossv = router.getLossRate() * 100.0 ;
|
double backplaneLossv = router.getLossRate() * 100.0 ;
|
||||||
|
backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
|
||||||
if (Double.isFinite(backplaneLossv)) {
|
if (Double.isFinite(backplaneLossv)) {
|
||||||
backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
|
|
||||||
backplaneLossRate.setValue(Math.min(backplaneLossRate.getValue().doubleValue() * 0.98 + backplaneLossv * 0.02, 101.0));
|
backplaneLossRate.setValue(Math.min(backplaneLossRate.getValue().doubleValue() * 0.98 + backplaneLossv * 0.02, 101.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新CPU
|
||||||
|
OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
double sys=osBean.getCpuLoad();
|
||||||
|
double proc=osBean.getProcessCpuLoad();
|
||||||
|
double load = proc/(1-sys+proc)* 100.0 ;
|
||||||
|
if (Double.isFinite(load)) {
|
||||||
|
CPUload.setValue(Math.min(CPUload.getValue().doubleValue() * 0.98 + load * 0.02, 101.0));
|
||||||
|
}
|
||||||
|
CPUloadText.setLabel(String.format("%.1f",load) + "%");
|
||||||
|
|
||||||
|
|
||||||
|
// 更新RAM
|
||||||
|
long max=Runtime.getRuntime().maxMemory();
|
||||||
|
long free=Runtime.getRuntime().freeMemory();
|
||||||
|
double ramUsage = (double) (max - free) /max* 100.0 ;
|
||||||
|
if (Double.isFinite(ramUsage)) {
|
||||||
|
RAMusage.setValue(Math.min(RAMusage.getValue().doubleValue() * 0.98 + ramUsage * 0.02, 101.0));
|
||||||
|
}
|
||||||
|
RAMusageText.setLabel(KLALBUtils.convertIBUint(max- free)+"/"+KLALBUtils.convertIBUint(max ) );
|
||||||
|
|
||||||
|
|
||||||
// 更新在线设备数
|
// 更新在线设备数
|
||||||
String contt = Long.toString(kc.getIpv6Router().getKlalbRouteProtol().getDevicesFound());
|
String contt = Long.toString(kc.getIpv6Router().getKlalbRouteProtol().getDevicesFound());
|
||||||
if (!contt.equals(devicesOnline.getText())) {
|
if (!contt.equals(devicesOnline.getText())) {
|
||||||
@@ -1538,9 +1615,19 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
Long vasn = kck.getVirtualASN();
|
Long vasn = kck.getVirtualASN();
|
||||||
asnFieldSet.setText(vasn != null ? vasn.toString() : "");
|
asnFieldSet.setText(vasn != null ? vasn.toString() : "");
|
||||||
|
|
||||||
|
enableTUN.setSelected(kck.isEnableTUN());
|
||||||
|
|
||||||
|
|
||||||
String tunname=kck.getTUNName();
|
String tunname=kck.getTUNName();
|
||||||
tunDeviceName.setText(tunname!=null?tunname:"");
|
tunDeviceName.setText(tunname!=null?tunname:"");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 加载Web API设置
|
||||||
|
webApiEnabled.setSelected(kck.isWebUI());
|
||||||
|
webListenSet.setText(kck.getWebListen() != null ? kck.getWebListen().toString()
|
||||||
|
: "http://0.0.0.0:4665");
|
||||||
|
|
||||||
// 加载TCP监听
|
// 加载TCP监听
|
||||||
MultiProtocolSocketAddress mpat = kck.getTCPListen();
|
MultiProtocolSocketAddress mpat = kck.getTCPListen();
|
||||||
tcpListeningSet.setText(mpat != null ? mpat.toString() : "");
|
tcpListeningSet.setText(mpat != null ? mpat.toString() : "");
|
||||||
@@ -1550,7 +1637,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
udpListeningSet.setText(mpau != null ? mpau.toString() : "");
|
udpListeningSet.setText(mpau != null ? mpau.toString() : "");
|
||||||
|
|
||||||
// 加载开放线路表
|
// 加载开放线路表
|
||||||
List<MultiProtocolSocketAddress> linet = kck.getLineTable();
|
List<MultiProtocolSocketAddress> linet = kck.getExternalEndpoints();
|
||||||
openLineTabelSet.setText(listToStr2(linet));
|
openLineTabelSet.setText(listToStr2(linet));
|
||||||
|
|
||||||
// 加载自动连接线路表
|
// 加载自动连接线路表
|
||||||
@@ -1579,9 +1666,9 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
}
|
}
|
||||||
linkConnectionsCount.getSlider().setValue(conc);
|
linkConnectionsCount.getSlider().setValue(conc);
|
||||||
|
|
||||||
denyQuery.setSelected( kck.isDenyLineTableQuery());
|
denyQuery.setSelected( kck.isDenyExternalEndpointQuery());
|
||||||
|
|
||||||
denyBroadcast.setSelected( kck.isDenyLineTableBroadcast());
|
denyBroadcast.setSelected( kck.isDenyExternalEndpointBroadcast());
|
||||||
|
|
||||||
String stategy= kck.getPerformanceStrategy();
|
String stategy= kck.getPerformanceStrategy();
|
||||||
PerformanceStrategy pfs=PerformanceStrategy.fromDescription(stategy);
|
PerformanceStrategy pfs=PerformanceStrategy.fromDescription(stategy);
|
||||||
@@ -1712,7 +1799,7 @@ public class KLALBStateGUI3 extends XFrame {
|
|||||||
public void close() {
|
public void close() {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
if (tsk != null) {
|
if (tsk != null) {
|
||||||
tsk.cancel();
|
tsk.cancel(false);
|
||||||
}
|
}
|
||||||
if (st != null) {
|
if (st != null) {
|
||||||
st.remove(ti);
|
st.remove(ti);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jfree.chart.plot.dial.DialTextAnnotation;
|
|||||||
import org.jfree.data.general.DefaultValueDataset;
|
import org.jfree.data.general.DefaultValueDataset;
|
||||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||||
import org.kne.cloud.network.klalb.CONST;
|
import org.kne.cloud.network.klalb.CONST;
|
||||||
|
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
import org.kne.cloud.network.klalb.KLALBUtils;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
import org.kne.cloud.network.perf.Kperf;
|
import org.kne.cloud.network.perf.Kperf;
|
||||||
@@ -35,17 +36,17 @@ import java.awt.event.ActionEvent;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
public class KperfGUI extends XFrame{
|
public class KperfGUI extends XFrame{
|
||||||
private static Timer tmr=new Timer();
|
|
||||||
|
|
||||||
private KperfReports reports=new KperfReportsImpl();
|
private KperfReports reports=new KperfReportsImpl();
|
||||||
private Kperf kperf;
|
private Kperf kperf;
|
||||||
private JTextField targetAddressField;
|
private JTextField targetAddressField;
|
||||||
private JButton startButton;
|
private JButton startButton;
|
||||||
private JProgressBar progressBar;
|
|
||||||
private DefaultValueDataset upSpeed;
|
private DefaultValueDataset upSpeed;
|
||||||
private DefaultValueDataset upDataSpeed;
|
private DefaultValueDataset upDataSpeed;
|
||||||
private DialTextAnnotation upSpeedText;
|
private DialTextAnnotation upSpeedText;
|
||||||
@@ -54,7 +55,7 @@ public class KperfGUI extends XFrame{
|
|||||||
private DialTextAnnotation downSpeedText;
|
private DialTextAnnotation downSpeedText;
|
||||||
private JTextField sourceAddressField;
|
private JTextField sourceAddressField;
|
||||||
|
|
||||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
private volatile SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
||||||
|
|
||||||
private DefaultValueDataset upPPS;
|
private DefaultValueDataset upPPS;
|
||||||
|
|
||||||
@@ -68,12 +69,8 @@ public class KperfGUI extends XFrame{
|
|||||||
|
|
||||||
private DialTextAnnotation downPPSText;
|
private DialTextAnnotation downPPSText;
|
||||||
|
|
||||||
private TimerTask tsk;
|
private ScheduledFuture<?> tsk;
|
||||||
private class KperfReportsImpl implements KperfReports{
|
private class KperfReportsImpl implements KperfReports{
|
||||||
@Override
|
|
||||||
public void testProcess(double process) {
|
|
||||||
progressBar.setValue((int) (process*100.0f));
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public void testFinish() {
|
public void testFinish() {
|
||||||
if(kperf!=null) {
|
if(kperf!=null) {
|
||||||
@@ -217,253 +214,11 @@ public class KperfGUI extends XFrame{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
upSpeed = new DefaultValueDataset(0);
|
|
||||||
upDataSpeed = new DefaultValueDataset(0);
|
|
||||||
DialPlot dpup = new DialPlot();
|
|
||||||
dpup.setDataset(1, upSpeed);
|
|
||||||
dpup.setDataset(0, upDataSpeed);
|
|
||||||
StandardDialFrame sdfs = new StandardDialFrame();
|
|
||||||
sdfs.setVisible(false);
|
|
||||||
dpup.setDialFrame(sdfs);
|
|
||||||
StandardDialScale sds = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
|
||||||
sds.setTickRadius(0.9);
|
|
||||||
sds.setTickLabelsVisible(false);
|
|
||||||
dpup.addScale(0, sds);
|
|
||||||
|
|
||||||
StandardDialRange sdrr = new StandardDialRange(0, 70, Color.GREEN);
|
|
||||||
sdrr.setInnerRadius(0.92);
|
|
||||||
sdrr.setOuterRadius(0.93);
|
|
||||||
dpup.addLayer(sdrr);
|
|
||||||
|
|
||||||
StandardDialRange sdrr2 = new StandardDialRange(70, 90, Color.YELLOW);
|
|
||||||
sdrr2.setInnerRadius(0.92);
|
|
||||||
sdrr2.setOuterRadius(0.93);
|
|
||||||
dpup.addLayer(sdrr2);
|
|
||||||
|
|
||||||
StandardDialRange sdrr3 = new StandardDialRange(90, 100, Color.RED);
|
|
||||||
sdrr3.setInnerRadius(0.92);
|
|
||||||
sdrr3.setOuterRadius(0.93);
|
|
||||||
dpup.addLayer(sdrr3);
|
|
||||||
|
|
||||||
DialPointer.Pointer dpd = new DialPointer.Pointer();
|
|
||||||
dpd.setRadius(0.8);
|
|
||||||
dpd.setFillPaint(new Color(127, 0, 0, 0));
|
|
||||||
dpd.setOutlinePaint(new Color(127, 0, 0));
|
|
||||||
dpd.setDatasetIndex(0);
|
|
||||||
//dpup.addLayer(dpd);
|
|
||||||
|
|
||||||
DialPointer.Pointer dp = new DialPointer.Pointer();
|
|
||||||
dp.setRadius(0.8);
|
|
||||||
dp.setFillPaint(Color.RED);
|
|
||||||
dp.setOutlinePaint(Color.RED);
|
|
||||||
dp.setDatasetIndex(1);
|
|
||||||
dpup.addLayer(dp);
|
|
||||||
|
|
||||||
upSpeedText = new DialTextAnnotation("0%");
|
|
||||||
upSpeedText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
|
||||||
dpup.addLayer(upSpeedText);
|
|
||||||
|
|
||||||
JFreeChart jfup = new JFreeChart(dpup);
|
|
||||||
jfup.setBorderPaint(Color.WHITE);
|
|
||||||
jfup.setTitle(UIEnv.getRsb().getString("uploadspeed"));
|
|
||||||
jfup.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
|
||||||
jfup.getTitle().setPosition(RectangleEdge.BOTTOM);
|
|
||||||
dpup.setView(0, 0, 1, 1);
|
|
||||||
ChartPanel cpup = new ChartPanel(jfup);
|
|
||||||
cpup.setPreferredSize(dashSize);
|
|
||||||
cpup.setSize(dashSize);
|
|
||||||
cpup.setMinimumSize(dashSize);
|
|
||||||
cpup.setBackground(Color.WHITE);
|
|
||||||
cpup.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
|
||||||
panel_3.add(cpup, BorderLayout.WEST);
|
|
||||||
|
|
||||||
downSpeed = new DefaultValueDataset(0);
|
|
||||||
downDataSpeed = new DefaultValueDataset(0);
|
|
||||||
DialPlot dpup1 = new DialPlot();
|
|
||||||
dpup1.setDataset(1, downSpeed);
|
|
||||||
dpup1.setDataset(0, downDataSpeed);
|
|
||||||
StandardDialFrame sdfs1 = new StandardDialFrame();
|
|
||||||
sdfs1.setVisible(false);
|
|
||||||
dpup1.setDialFrame(sdfs1);
|
|
||||||
StandardDialScale sds1 = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
|
||||||
sds1.setTickRadius(0.9);
|
|
||||||
sds1.setTickLabelsVisible(false);
|
|
||||||
dpup1.addScale(0, sds1);
|
|
||||||
|
|
||||||
StandardDialRange sdrr1 = new StandardDialRange(0, 70, Color.GREEN);
|
|
||||||
sdrr1.setInnerRadius(0.92);
|
|
||||||
sdrr1.setOuterRadius(0.93);
|
|
||||||
dpup1.addLayer(sdrr1);
|
|
||||||
|
|
||||||
StandardDialRange sdrr21 = new StandardDialRange(70, 90, Color.YELLOW);
|
|
||||||
sdrr21.setInnerRadius(0.92);
|
|
||||||
sdrr21.setOuterRadius(0.93);
|
|
||||||
dpup1.addLayer(sdrr21);
|
|
||||||
|
|
||||||
StandardDialRange sdrr31 = new StandardDialRange(90, 100, Color.RED);
|
|
||||||
sdrr31.setInnerRadius(0.92);
|
|
||||||
sdrr31.setOuterRadius(0.93);
|
|
||||||
dpup1.addLayer(sdrr31);
|
|
||||||
|
|
||||||
DialPointer.Pointer dp11 = new DialPointer.Pointer();
|
|
||||||
dp11.setRadius(0.8);
|
|
||||||
dp11.setFillPaint(new Color(0, 127, 0, 0));
|
|
||||||
dp11.setOutlinePaint(new Color(0, 127, 0));
|
|
||||||
dp11.setDatasetIndex(0);
|
|
||||||
//dpup1.addLayer(dp11);
|
|
||||||
|
|
||||||
DialPointer.Pointer dp1 = new DialPointer.Pointer();
|
|
||||||
dp1.setRadius(0.8);
|
|
||||||
dp1.setFillPaint(Color.GREEN);
|
|
||||||
dp1.setOutlinePaint(Color.GREEN);
|
|
||||||
dp1.setDatasetIndex(1);
|
|
||||||
dpup1.addLayer(dp1);
|
|
||||||
|
|
||||||
downSpeedText = new DialTextAnnotation("0%");
|
|
||||||
downSpeedText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
|
||||||
dpup1.addLayer(downSpeedText);
|
|
||||||
|
|
||||||
JFreeChart jfup1 = new JFreeChart(dpup1);
|
|
||||||
jfup1.setBorderPaint(Color.WHITE);
|
|
||||||
jfup1.setTitle(UIEnv.getRsb().getString("downloadspeed"));
|
|
||||||
jfup1.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
|
||||||
jfup1.getTitle().setPosition(RectangleEdge.BOTTOM);
|
|
||||||
dpup1.setView(0, 0, 1, 1);
|
|
||||||
ChartPanel cpup1 = new ChartPanel(jfup1);
|
|
||||||
cpup1.setPreferredSize(dashSize);
|
|
||||||
cpup1.setSize(dashSize);
|
|
||||||
cpup1.setMinimumSize(dashSize);
|
|
||||||
cpup1.setBackground(Color.WHITE);
|
|
||||||
cpup1.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
|
||||||
panel_4.add(cpup1, BorderLayout.WEST);
|
|
||||||
|
|
||||||
}
|
|
||||||
{
|
|
||||||
upPPS = new DefaultValueDataset(0);
|
|
||||||
upDataPPS = new DefaultValueDataset(0);
|
|
||||||
DialPlot dpup = new DialPlot();
|
|
||||||
dpup.setDataset(1, upPPS);
|
|
||||||
dpup.setDataset(0, upDataPPS);
|
|
||||||
StandardDialFrame sdfs = new StandardDialFrame();
|
|
||||||
sdfs.setVisible(false);
|
|
||||||
dpup.setDialFrame(sdfs);
|
|
||||||
StandardDialScale sds = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
|
||||||
sds.setTickRadius(0.9);
|
|
||||||
sds.setTickLabelsVisible(false);
|
|
||||||
dpup.addScale(0, sds);
|
|
||||||
|
|
||||||
StandardDialRange sdrr = new StandardDialRange(0, 70, Color.GREEN);
|
|
||||||
sdrr.setInnerRadius(0.92);
|
|
||||||
sdrr.setOuterRadius(0.93);
|
|
||||||
dpup.addLayer(sdrr);
|
|
||||||
|
|
||||||
StandardDialRange sdrr2 = new StandardDialRange(70, 90, Color.YELLOW);
|
|
||||||
sdrr2.setInnerRadius(0.92);
|
|
||||||
sdrr2.setOuterRadius(0.93);
|
|
||||||
dpup.addLayer(sdrr2);
|
|
||||||
|
|
||||||
StandardDialRange sdrr3 = new StandardDialRange(90, 100, Color.RED);
|
|
||||||
sdrr3.setInnerRadius(0.92);
|
|
||||||
sdrr3.setOuterRadius(0.93);
|
|
||||||
dpup.addLayer(sdrr3);
|
|
||||||
|
|
||||||
DialPointer.Pointer dp1 = new DialPointer.Pointer();
|
|
||||||
dp1.setRadius(0.8);
|
|
||||||
dp1.setFillPaint(new Color(127, 0, 0, 0));
|
|
||||||
dp1.setOutlinePaint(new Color(127, 0, 0));
|
|
||||||
dp1.setDatasetIndex(0);
|
|
||||||
//dpup.addLayer(dp1);
|
|
||||||
|
|
||||||
DialPointer.Pointer dp = new DialPointer.Pointer();
|
|
||||||
dp.setRadius(0.8);
|
|
||||||
dp.setFillPaint(Color.RED);
|
|
||||||
dp.setOutlinePaint(Color.RED);
|
|
||||||
dp.setDatasetIndex(1);
|
|
||||||
dpup.addLayer(dp);
|
|
||||||
|
|
||||||
upPPSText = new DialTextAnnotation("0PPS");
|
|
||||||
upPPSText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
|
||||||
dpup.addLayer(upPPSText);
|
|
||||||
|
|
||||||
JFreeChart jfup = new JFreeChart(dpup);
|
|
||||||
jfup.setBorderPaint(Color.WHITE);
|
|
||||||
jfup.setTitle(UIEnv.getRsb().getString("uploadpps"));
|
|
||||||
jfup.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
|
||||||
jfup.getTitle().setPosition(RectangleEdge.BOTTOM);
|
|
||||||
dpup.setView(0, 0, 1, 1);
|
|
||||||
ChartPanel cpup = new ChartPanel(jfup);
|
|
||||||
cpup.setPreferredSize(dashSize);
|
|
||||||
cpup.setSize(cpup.getPreferredSize());
|
|
||||||
cpup.setBackground(Color.WHITE);
|
|
||||||
cpup.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
|
||||||
panel_5.add(cpup, BorderLayout.WEST);
|
|
||||||
|
|
||||||
downPPS = new DefaultValueDataset(0);
|
|
||||||
downDataPPS = new DefaultValueDataset(0);
|
|
||||||
DialPlot dpup1 = new DialPlot();
|
|
||||||
dpup1.setDataset(1, downPPS);
|
|
||||||
dpup1.setDataset(0, downDataPPS);
|
|
||||||
StandardDialFrame sdfs1 = new StandardDialFrame();
|
|
||||||
sdfs1.setVisible(false);
|
|
||||||
dpup1.setDialFrame(sdfs1);
|
|
||||||
StandardDialScale sds1 = new StandardDialScale(0, 100, -120, -300, 10, 5);
|
|
||||||
sds1.setTickRadius(0.9);
|
|
||||||
sds1.setTickLabelsVisible(false);
|
|
||||||
dpup1.addScale(0, sds1);
|
|
||||||
|
|
||||||
StandardDialRange sdrr1 = new StandardDialRange(0, 70, Color.GREEN);
|
|
||||||
sdrr1.setInnerRadius(0.92);
|
|
||||||
sdrr1.setOuterRadius(0.93);
|
|
||||||
dpup1.addLayer(sdrr1);
|
|
||||||
|
|
||||||
StandardDialRange sdrr21 = new StandardDialRange(70, 90, Color.YELLOW);
|
|
||||||
sdrr21.setInnerRadius(0.92);
|
|
||||||
sdrr21.setOuterRadius(0.93);
|
|
||||||
dpup1.addLayer(sdrr21);
|
|
||||||
|
|
||||||
StandardDialRange sdrr31 = new StandardDialRange(90, 100, Color.RED);
|
|
||||||
sdrr31.setInnerRadius(0.92);
|
|
||||||
sdrr31.setOuterRadius(0.93);
|
|
||||||
dpup1.addLayer(sdrr31);
|
|
||||||
|
|
||||||
DialPointer.Pointer dp111 = new DialPointer.Pointer();
|
|
||||||
dp111.setRadius(0.8);
|
|
||||||
dp111.setFillPaint(new Color(0, 127, 0, 0));
|
|
||||||
dp111.setOutlinePaint(new Color(0, 127, 0));
|
|
||||||
dp111.setDatasetIndex(0);
|
|
||||||
///dpup1.addLayer(dp111);
|
|
||||||
DialPointer.Pointer dp11 = new DialPointer.Pointer();
|
|
||||||
dp11.setRadius(0.8);
|
|
||||||
dp11.setFillPaint(Color.GREEN);
|
|
||||||
dp11.setOutlinePaint(Color.GREEN);
|
|
||||||
dp11.setDatasetIndex(1);
|
|
||||||
dpup1.addLayer(dp11);
|
|
||||||
|
|
||||||
downPPSText = new DialTextAnnotation("0PPS");
|
|
||||||
downPPSText.setFont(UIEnv.getFont().deriveFont(20.0f));
|
|
||||||
dpup1.addLayer(downPPSText);
|
|
||||||
|
|
||||||
JFreeChart jfup1 = new JFreeChart(dpup1);
|
|
||||||
jfup1.setBorderPaint(Color.WHITE);
|
|
||||||
jfup1.setTitle(UIEnv.getRsb().getString("downloadpps"));
|
|
||||||
jfup1.getTitle().setFont(UIEnv.getFont().deriveFont(22.0f));
|
|
||||||
jfup1.getTitle().setPosition(RectangleEdge.BOTTOM);
|
|
||||||
dpup1.setView(0, 0, 1, 1);
|
|
||||||
ChartPanel cpup1 = new ChartPanel(jfup1);
|
|
||||||
cpup1.setPreferredSize(dashSize);
|
|
||||||
cpup1.setSize(cpup1.getPreferredSize());
|
|
||||||
cpup1.setBackground(Color.WHITE);
|
|
||||||
cpup1.setBorder(new LineBorder(Color.LIGHT_GRAY));
|
|
||||||
panel_6.add(cpup1, BorderLayout.WEST);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
// 上行速度仪表盘
|
// 上行速度仪表盘
|
||||||
upSpeed = new DefaultValueDataset(0);
|
upSpeed = new DefaultValueDataset(0);
|
||||||
upDataSpeed = new DefaultValueDataset(0);
|
upDataSpeed = new DefaultValueDataset(0);
|
||||||
DialPanel dialup=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadspeed"), upSpeed, upDataSpeed, Color.RED, new Color(127, 0, 0));
|
DialPanel dialup=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadspeed"), upSpeed, null, Color.RED, new Color(127, 0, 0));
|
||||||
dialup.addGradientRanges(UIEnv.RANGE_1);
|
dialup.addGradientRanges(UIEnv.RANGE_1);
|
||||||
upSpeedText =dialup.getTextAnnotation();
|
upSpeedText =dialup.getTextAnnotation();
|
||||||
|
|
||||||
@@ -474,7 +229,7 @@ public class KperfGUI extends XFrame{
|
|||||||
// 下行速度仪表盘
|
// 下行速度仪表盘
|
||||||
downSpeed = new DefaultValueDataset(0);
|
downSpeed = new DefaultValueDataset(0);
|
||||||
downDataSpeed = new DefaultValueDataset(0);
|
downDataSpeed = new DefaultValueDataset(0);
|
||||||
DialPanel dialdown=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadspeed"), downSpeed, downDataSpeed, Color.GREEN, new Color(0, 127, 0));
|
DialPanel dialdown=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadspeed"), downSpeed, null, Color.GREEN, new Color(0, 127, 0));
|
||||||
dialdown.addGradientRanges(UIEnv.RANGE_1);
|
dialdown.addGradientRanges(UIEnv.RANGE_1);
|
||||||
downSpeedText =dialdown.getTextAnnotation();
|
downSpeedText =dialdown.getTextAnnotation();
|
||||||
|
|
||||||
@@ -484,7 +239,7 @@ public class KperfGUI extends XFrame{
|
|||||||
// 上行包速率仪表盘
|
// 上行包速率仪表盘
|
||||||
upPPS = new DefaultValueDataset(0);
|
upPPS = new DefaultValueDataset(0);
|
||||||
upDataPPS = new DefaultValueDataset(0);
|
upDataPPS = new DefaultValueDataset(0);
|
||||||
DialPanel dialupPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadpps"), upPPS, upDataPPS, Color.RED, new Color(127, 0, 0));
|
DialPanel dialupPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("uploadpps"), upPPS, null, Color.RED, new Color(127, 0, 0));
|
||||||
dialupPPS.addGradientRanges(UIEnv.RANGE_1);
|
dialupPPS.addGradientRanges(UIEnv.RANGE_1);
|
||||||
upPPSText = dialupPPS.getTextAnnotation();
|
upPPSText = dialupPPS.getTextAnnotation();
|
||||||
|
|
||||||
@@ -493,7 +248,7 @@ public class KperfGUI extends XFrame{
|
|||||||
// 下行包速率仪表盘
|
// 下行包速率仪表盘
|
||||||
downPPS = new DefaultValueDataset(0);
|
downPPS = new DefaultValueDataset(0);
|
||||||
downDataPPS = new DefaultValueDataset(0);
|
downDataPPS = new DefaultValueDataset(0);
|
||||||
DialPanel dialdownPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadpps"), downPPS, downDataPPS, Color.GREEN, new Color(0, 127, 0));
|
DialPanel dialdownPPS=new DialPanel(CONST.dialwidth, UIEnv.getRsb().getString("downloadpps"), downPPS, null, Color.GREEN, new Color(0, 127, 0));
|
||||||
dialdownPPS.addGradientRanges(UIEnv.RANGE_1);
|
dialdownPPS.addGradientRanges(UIEnv.RANGE_1);
|
||||||
downPPSText = dialdownPPS.getTextAnnotation();
|
downPPSText = dialdownPPS.getTextAnnotation();
|
||||||
|
|
||||||
@@ -521,9 +276,6 @@ public class KperfGUI extends XFrame{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
progressBar = new JProgressBar();
|
|
||||||
progressBar.setPreferredSize(new Dimension(100, 5));
|
|
||||||
getContentPane().add(progressBar, BorderLayout.NORTH);
|
|
||||||
getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
|
getTitlelabel().setFont(UIEnv.getFont().deriveFont(17.0f));
|
||||||
getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));
|
getTitlepanel().setBorder(new LineBorder(Color.LIGHT_GRAY));
|
||||||
getTitlelabel().setForeground(Color.WHITE);
|
getTitlelabel().setForeground(Color.WHITE);
|
||||||
@@ -532,38 +284,37 @@ public class KperfGUI extends XFrame{
|
|||||||
setSize(CONST.windowwidth,CONST.windowheight );
|
setSize(CONST.windowwidth,CONST.windowheight );
|
||||||
setResizable(false);
|
setResizable(false);
|
||||||
setLocationRelativeTo(comp);
|
setLocationRelativeTo(comp);
|
||||||
tsk=new TimerTask() {
|
tsk=KLALBScheduler.getScheduler().scheduleWithFixedDelay(new TimerTask() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if(monitor!=null) {
|
if(monitor!=null) {
|
||||||
double outload = monitor.getOutSpeed() * 100.0 / monitor.getOutSpeedMax();
|
double outload = monitor.getOutSpeed() * 100.0 / monitor.getOutSpeedMax();
|
||||||
if (Double.isFinite(outload)) {
|
upSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getOutSpeed()) + "/s");
|
||||||
upSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getOutSpeed()) + "/s");
|
if (Double.isFinite(outload)) {
|
||||||
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
upSpeed.setValue(Math.min(upSpeed.getValue().doubleValue() * 0.98 + outload * 0.02, 101.0));
|
||||||
}
|
|
||||||
|
|
||||||
double inload = monitor.getInSpeed() * 100.0 / monitor.getInSpeedMax();
|
|
||||||
if (Double.isFinite(inload)) {
|
|
||||||
downSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getInSpeed()) + "/s");
|
|
||||||
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
double outPPSload = monitor.getOutPPS() * 100.0 / monitor.getOutPPSMax();
|
|
||||||
if (Double.isFinite(outPPSload)) {
|
|
||||||
upPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getOutPPS()) + "PPS");
|
|
||||||
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
double inPPSload = monitor.getInPPS() * 100.0 / monitor.getInPPSMax();
|
|
||||||
if (Double.isFinite(inPPSload)) {
|
|
||||||
downPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getInPPS()) + "PPS");
|
|
||||||
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
tmr.scheduleAtFixedRate(tsk, 200, 100);
|
double inload = monitor.getInSpeed() * 100.0 / monitor.getInSpeedMax();
|
||||||
|
downSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getInSpeed()) + "/s");
|
||||||
|
if (Double.isFinite(inload)) {
|
||||||
|
downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
double outPPSload = monitor.getOutPPS() * 100.0 / monitor.getOutPPSMax();
|
||||||
|
upPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getOutPPS()) + "PPS");
|
||||||
|
if (Double.isFinite(outPPSload)) {
|
||||||
|
upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
double inPPSload = monitor.getInPPS() * 100.0 / monitor.getInPPSMax();
|
||||||
|
downPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getInPPS()) + "PPS");
|
||||||
|
if (Double.isFinite(inPPSload)) {
|
||||||
|
downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 200, 100, TimeUnit.MILLISECONDS);
|
||||||
addWindowListener(new WindowListener() {
|
addWindowListener(new WindowListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -593,7 +344,7 @@ public class KperfGUI extends XFrame{
|
|||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent e) {
|
public void windowClosing(WindowEvent e) {
|
||||||
if(tsk!=null)
|
if(tsk!=null)
|
||||||
tsk.cancel();
|
tsk.cancel(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import java.awt.Color;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.GridLayout;
|
import java.awt.GridLayout;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Timer;
|
import java.util.Scanner;
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
@@ -18,11 +17,15 @@ import org.jfree.chart.JFreeChart;
|
|||||||
import org.jfree.data.time.Millisecond;
|
import org.jfree.data.time.Millisecond;
|
||||||
import org.jfree.data.time.TimeSeries;
|
import org.jfree.data.time.TimeSeries;
|
||||||
import org.jfree.data.time.TimeSeriesCollection;
|
import org.jfree.data.time.TimeSeriesCollection;
|
||||||
|
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
||||||
|
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
||||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||||
|
import org.kne.cloud.network.congestion.Vegas2CongestionAlgorithm;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||||
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
import org.kne.cloud.network.klalb.KLALBRemoteLink;
|
import org.kne.cloud.network.klalb.KLALBRemoteLink;
|
||||||
|
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||||
import org.kne.cloud.network.monitor.LinkStatus;
|
import org.kne.cloud.network.monitor.LinkStatus;
|
||||||
import org.kne.cloud.network.monitor.TimestampMonitorValue;
|
import org.kne.cloud.network.monitor.TimestampMonitorValue;
|
||||||
import org.kne.math.Long128;
|
import org.kne.math.Long128;
|
||||||
@@ -35,19 +38,18 @@ import javax.swing.ImageIcon;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.awt.event.WindowListener;
|
import java.awt.event.WindowListener;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.swing.JSlider;
|
import javax.swing.JSlider;
|
||||||
|
|
||||||
public class LineMonitorGUI extends XFrame {
|
public class LineMonitorGUI extends XFrame {
|
||||||
private Timer timer;
|
private ScheduledFuture<?> tsk3;
|
||||||
private Timer timer1;
|
|
||||||
private Timer timer2;
|
|
||||||
private Timer timer3;
|
|
||||||
private TimerTask tsk3;
|
|
||||||
|
|
||||||
private TimerTask tsk4, tsk5,tsk6;
|
private ScheduledFuture<?> tsk4, tsk5,tsk6,tsk7;
|
||||||
private TimerTask d1;
|
private ScheduledFuture<?> d1;
|
||||||
private TimerTask d2;
|
private ScheduledFuture<?> d2;
|
||||||
private TimerTask d3;
|
private ScheduledFuture<?> d3;
|
||||||
|
private ScheduledFuture<?> d4;
|
||||||
|
|
||||||
private TimeSeries spdup = new TimeSeries(UIEnv.getRsb().getString("uploadspeed"));
|
private TimeSeries spdup = new TimeSeries(UIEnv.getRsb().getString("uploadspeed"));
|
||||||
private TimeSeries spddown = new TimeSeries(UIEnv.getRsb().getString("downloadspeed"));
|
private TimeSeries spddown = new TimeSeries(UIEnv.getRsb().getString("downloadspeed"));
|
||||||
@@ -62,13 +64,22 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
private TimeSeries queueused = new TimeSeries(UIEnv.getRsb().getString("queueused"));
|
private TimeSeries queueused = new TimeSeries(UIEnv.getRsb().getString("queueused"));
|
||||||
private TimeSeries buffermax = new TimeSeries(UIEnv.getRsb().getString("maxbuffer"));
|
private TimeSeries buffermax = new TimeSeries(UIEnv.getRsb().getString("maxbuffer"));
|
||||||
|
|
||||||
|
|
||||||
|
private TimeSeries rttbaseline = new TimeSeries(UIEnv.getRsb().getString("rttbaseline"));
|
||||||
|
private TimeSeries rtt = new TimeSeries(UIEnv.getRsb().getString("rtt"));
|
||||||
|
private TimeSeries rttmin=new TimeSeries(UIEnv.getRsb().getString("rttmin"));
|
||||||
|
private TimeSeries rttmax=new TimeSeries(UIEnv.getRsb().getString("rttmax"));
|
||||||
|
private TimeSeries rto=new TimeSeries(UIEnv.getRsb().getString("rto"));
|
||||||
|
|
||||||
private KLALBRemoteLink tr;
|
private KLALBRemoteLink tr;
|
||||||
private JFreeChart jfc;
|
private JFreeChart jfc;
|
||||||
private JFreeChart jfce;
|
private JFreeChart jfce;
|
||||||
private JFreeChart jbfc;
|
private JFreeChart jbfc;
|
||||||
|
private JFreeChart jbfcv;
|
||||||
private JLabel spdp;
|
private JLabel spdp;
|
||||||
private JLabel delp;
|
private JLabel delp;
|
||||||
private JLabel sbpdp;
|
private JLabel sbpdp;
|
||||||
|
private JLabel sbpdpv;
|
||||||
private long timeRange = 5000;
|
private long timeRange = 5000;
|
||||||
private long[] values = new long[] { 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 };
|
private long[] values = new long[] { 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000 };
|
||||||
private JPanel panel_1;
|
private JPanel panel_1;
|
||||||
@@ -155,6 +166,24 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
jp.add(sbpdp);
|
jp.add(sbpdp);
|
||||||
|
|
||||||
|
|
||||||
|
TimeSeriesCollection tbsc1 = new TimeSeriesCollection();
|
||||||
|
tbsc1.addSeries(rttbaseline);
|
||||||
|
tbsc1.addSeries(rtt);
|
||||||
|
tbsc1.addSeries(rttmax);
|
||||||
|
tbsc1.addSeries(rttmin);
|
||||||
|
tbsc1.addSeries(rto);
|
||||||
|
jbfcv = ChartFactory.createTimeSeriesChart(UIEnv.getRsb().getString("congestionmonitor"),
|
||||||
|
UIEnv.getRsb().getString("time") + "(s)", UIEnv.getRsb().getString("delay") + "(ms)", tbsc1);
|
||||||
|
jbfcv.getXYPlot().setBackgroundPaint(Color.BLACK);
|
||||||
|
jbfcv.getXYPlot().getRenderer().setSeriesPaint(0, Color.CYAN);
|
||||||
|
jbfcv.getXYPlot().getRenderer().setSeriesPaint(1, Color.YELLOW);
|
||||||
|
jbfcv.getXYPlot().getRenderer().setSeriesPaint(2, Color.RED);
|
||||||
|
jbfcv.getXYPlot().getRenderer().setSeriesPaint(3, Color.GREEN);
|
||||||
|
jbfcv.getXYPlot().getRenderer().setSeriesPaint(4, Color.ORANGE);
|
||||||
|
changeFont(jbfcv);
|
||||||
|
sbpdpv = new JLabel();
|
||||||
|
sbpdpv.setBorder(new LineBorder(Color.DARK_GRAY));
|
||||||
|
jp.add(sbpdpv);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -262,6 +291,14 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
buffermax.setMaximumItemCount((int) timeRange/5);
|
buffermax.setMaximumItemCount((int) timeRange/5);
|
||||||
queueused.setMaximumItemCount((int) timeRange/5);
|
queueused.setMaximumItemCount((int) timeRange/5);
|
||||||
}
|
}
|
||||||
|
synchronized (jbfcv) {
|
||||||
|
|
||||||
|
jbfcv.getXYPlot().getDomainAxis().setFixedAutoRange(timeRange);
|
||||||
|
bufferused.setMaximumItemCount((int) timeRange/5);
|
||||||
|
buffermax.setMaximumItemCount((int) timeRange/5);
|
||||||
|
queueused.setMaximumItemCount((int) timeRange/5);
|
||||||
|
}
|
||||||
|
|
||||||
windowSelect.setText(timeRange / 1000 + "s");
|
windowSelect.setText(timeRange / 1000 + "s");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,44 +365,70 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void recordCongestionData() {
|
||||||
|
if (isVisible()) {
|
||||||
|
Millisecond ms = new Millisecond(
|
||||||
|
new Date(tr.getMonitor().getClock().getCurrentTimeMillis()));
|
||||||
|
synchronized (jbfcv) {
|
||||||
|
CongestionAlgorithm window=tr.getWindow().getAlgorithm();
|
||||||
|
if(window !=null) {
|
||||||
|
double baseRTT = window.getBaseRTT();
|
||||||
|
rttbaseline.addOrUpdate(ms, baseRTT / 1000000.0);
|
||||||
|
rtt.addOrUpdate(ms, window.getCurrentRTT() / 1000000.0);
|
||||||
|
rto.addOrUpdate(ms, window.getRTO() / 1000000.0);
|
||||||
|
if (window instanceof DetnetCongestionAlgorithm) {
|
||||||
|
|
||||||
|
|
||||||
|
Vegas2CongestionAlgorithm deta = (Vegas2CongestionAlgorithm) window;
|
||||||
|
rttmax.addOrUpdate(ms, baseRTT * deta.getUpperDelayBound() / 1000000.0);
|
||||||
|
rttmin.addOrUpdate(ms, baseRTT * deta.getLowerDelayBound() / 1000000.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean b) {
|
public void setVisible(boolean b) {
|
||||||
if (b) {
|
if (b) {
|
||||||
if (timer == null) {
|
if (tsk3 == null) {
|
||||||
timer = new Timer();
|
|
||||||
timer1 = new Timer();
|
tsk3 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
timer2 = new Timer();
|
|
||||||
timer3 = new Timer();
|
|
||||||
tsk3 = new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
updateTraffic();
|
updateTraffic();
|
||||||
}
|
}
|
||||||
};
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
tsk4 = new TimerTask() {
|
tsk4 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recordSpeedData();
|
recordSpeedData();
|
||||||
}
|
}
|
||||||
};
|
}, 10, 10, TimeUnit.MILLISECONDS);;
|
||||||
|
|
||||||
tsk5 = new TimerTask() {
|
tsk5 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recordDelayData();
|
recordDelayData();
|
||||||
}
|
}
|
||||||
};
|
}, 10, 10, TimeUnit.MILLISECONDS);
|
||||||
tsk6 = new TimerTask() {
|
tsk6 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recordBufferData();
|
recordBufferData();
|
||||||
}
|
}
|
||||||
};
|
}, 10, 10, TimeUnit.MILLISECONDS);
|
||||||
d1 = new TimerTask() {
|
tsk7 = KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
recordCongestionData();
|
||||||
|
}
|
||||||
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
|
d1 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -377,8 +440,8 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
} ,25, 25, TimeUnit.MILLISECONDS);
|
||||||
d2 = new TimerTask() {
|
d2 = KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -391,8 +454,8 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
d3 = new TimerTask() {
|
d3 = KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -405,40 +468,46 @@ public class LineMonitorGUI extends XFrame {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
timer.scheduleAtFixedRate(tsk3, 25, 25);
|
d4 =KLALBScheduler.getScheduler().scheduleWithFixedDelay( new Runnable() {
|
||||||
timer1.scheduleAtFixedRate(tsk4, 10, 10);
|
|
||||||
timer1.scheduleAtFixedRate(d1, 25, 25);
|
@Override
|
||||||
timer2.scheduleAtFixedRate(tsk5, 10, 10);
|
public void run() {
|
||||||
timer2.scheduleAtFixedRate(d2, 25, 25);
|
if (isVisible()) {
|
||||||
timer3.scheduleAtFixedRate(tsk6, 10, 10);
|
synchronized (jbfcv) {
|
||||||
timer3.scheduleAtFixedRate(d3, 25, 25);
|
ImageIcon i3 = new ImageIcon(
|
||||||
|
jbfcv.createBufferedImage(sbpdpv.getWidth(), sbpdpv.getHeight()));
|
||||||
|
sbpdpv.setIcon(i3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 25, 25, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (tsk3 != null)
|
if (tsk3 != null)
|
||||||
tsk3.cancel();
|
tsk3.cancel(false);
|
||||||
if (tsk4 != null)
|
if (tsk4 != null)
|
||||||
tsk4.cancel();
|
tsk4.cancel(false);
|
||||||
if (tsk5 != null)
|
if (tsk5 != null)
|
||||||
tsk5.cancel();
|
tsk5.cancel(false);
|
||||||
|
if (tsk6 != null)
|
||||||
|
tsk6.cancel(false);
|
||||||
|
if (tsk7 != null)
|
||||||
|
tsk7.cancel(false);
|
||||||
if (d1 != null)
|
if (d1 != null)
|
||||||
d1.cancel();
|
d1.cancel(false);
|
||||||
if (d2 != null)
|
if (d2 != null)
|
||||||
d2.cancel();
|
d2.cancel(false);
|
||||||
if (d3 != null)
|
if (d3 != null)
|
||||||
d3.cancel();
|
d3.cancel(false);
|
||||||
if (timer != null)
|
if (d4 != null)
|
||||||
timer.cancel();
|
d4.cancel(false);
|
||||||
if (timer1 != null)
|
tsk3=null;
|
||||||
timer1.cancel();
|
|
||||||
|
|
||||||
if (timer2 != null)
|
|
||||||
timer2.cancel();
|
|
||||||
|
|
||||||
if (timer3 != null)
|
|
||||||
timer3.cancel();
|
|
||||||
timer = null;
|
|
||||||
}
|
}
|
||||||
super.setVisible(b);
|
super.setVisible(b);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ public class NetworkGraphPanel extends GraphPanel {
|
|||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
KperfGUI kpfg=new KperfGUI();
|
KperfGUI kpfg=new KperfGUI();
|
||||||
kpfg.setVisible(true);
|
kpfg.setVisible(true);
|
||||||
MultiProtocolSocketAddress source=new MultiProtocolSocketAddress("KLALB_Stream",controller.getIpv6Router().getLocator().getAddress().toString(),0);
|
MultiProtocolSocketAddress source=new MultiProtocolSocketAddress("kltp",controller.getIpv6Router().getLocator().getAddress().toString(),0);
|
||||||
MultiProtocolSocketAddress target=new MultiProtocolSocketAddress("KLALB_Stream", address.toString(), 4564);
|
MultiProtocolSocketAddress target=new MultiProtocolSocketAddress("kltp", address.toString(), 4564);
|
||||||
kpfg.setTarget(target,source);
|
kpfg.setTarget(target,source);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -164,7 +164,7 @@ public class NetworkGraphPanel extends GraphPanel {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private double nsPerPixel=1000L;
|
private double nsPerPixel=5000L;
|
||||||
private class InetGraphEdgeGroup extends GraphEdgeGroup{
|
private class InetGraphEdgeGroup extends GraphEdgeGroup{
|
||||||
public InetGraphEdgeGroup(GraphNode nodeA, GraphNode nodeB) {
|
public InetGraphEdgeGroup(GraphNode nodeA, GraphNode nodeB) {
|
||||||
super(nodeA, nodeB);
|
super(nodeA, nodeB);
|
||||||
|
|||||||
@@ -73,19 +73,15 @@ public class NodeInformationPanel extends JPanel {
|
|||||||
overviewArea.setWrapStyleWord(true);
|
overviewArea.setWrapStyleWord(true);
|
||||||
overviewArea.setFont(UIEnv.getFont().deriveFont(14.0f));
|
overviewArea.setFont(UIEnv.getFont().deriveFont(14.0f));
|
||||||
overviewArea.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
overviewArea.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
||||||
StringBuilder sb=new StringBuilder();
|
|
||||||
sb.append(UIEnv.getRsb().getString("ipv6addr")).append(": ").append(address.toCompressedString()).append('\n');
|
|
||||||
String dname=controller.getIpv6Router().getKlalbRouteProtol().getDeviceName(address);
|
String dname=controller.getIpv6Router().getKlalbRouteProtol().getDeviceName(address);
|
||||||
if(dname!=null) {
|
String ddesc=null;
|
||||||
sb.append('\n').append(UIEnv.getRsb().getString("devicename")).append(": ").append(dname).append('\n');
|
|
||||||
}
|
|
||||||
if(address.equals(controller.getIpv6Router().getLocator().getAddress())&&controller.getConfigItem()!=null) {
|
if(address.equals(controller.getIpv6Router().getLocator().getAddress())&&controller.getConfigItem()!=null) {
|
||||||
String ddesc=controller.getConfigItem().getDeviceDescription();
|
ddesc=controller.getConfigItem().getDeviceDescription();
|
||||||
if(ddesc!=null&&!ddesc.isEmpty()) {
|
if(ddesc!=null&&ddesc.isEmpty()) {
|
||||||
sb.append('\n').append(UIEnv.getRsb().getString("devicedescription")).append(":\n").append(ddesc).append('\n');
|
ddesc=null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
overviewArea.setText(sb.toString());
|
overviewArea.setText(buildOverviewText(dname, ddesc));
|
||||||
panel.add(new JScrollPane(overviewArea), BorderLayout.CENTER);
|
panel.add(new JScrollPane(overviewArea), BorderLayout.CENTER);
|
||||||
|
|
||||||
JPanel panel_1 = new JPanel();
|
JPanel panel_1 = new JPanel();
|
||||||
@@ -169,16 +165,38 @@ public class NodeInformationPanel extends JPanel {
|
|||||||
|
|
||||||
client=new KLALBRoutingProtocolAPIClient(controller.getIpv6Router().getKlalbRouteProtol());
|
client=new KLALBRoutingProtocolAPIClient(controller.getIpv6Router().getKlalbRouteProtol());
|
||||||
try {
|
try {
|
||||||
client.requestOpenLines(new InetSocketAddress( address.toInet6Address(), KLALBRoutingProtocol.DEFAULT_PORT), (result)->{
|
client.requestNodeInfoFull(new InetSocketAddress( address.toInet6Address(), KLALBRoutingProtocol.DEFAULT_PORT), (info)->{
|
||||||
listModel.clear();
|
listModel.clear();
|
||||||
for (MultiProtocolSocketAddress multiProtocolSocketAddress : result) {
|
for (MultiProtocolSocketAddress multiProtocolSocketAddress : info.getOpenLines()) {
|
||||||
listModel.addElement(multiProtocolSocketAddress);
|
listModel.addElement(multiProtocolSocketAddress);
|
||||||
}
|
}
|
||||||
|
// 用对端返回的设备名称/描述更新概览(旧版本节点无该字段时保留原显示)
|
||||||
|
String dn=info.getDeviceName();
|
||||||
|
if(dn==null||dn.isEmpty()) {
|
||||||
|
dn=controller.getIpv6Router().getKlalbRouteProtol().getDeviceName(address);
|
||||||
|
}
|
||||||
|
String dd=info.getDeviceDescription();
|
||||||
|
if(dd!=null&&dd.isEmpty()) {
|
||||||
|
dd=null;
|
||||||
|
}
|
||||||
|
overviewArea.setText(buildOverviewText(dn, dd));
|
||||||
});
|
});
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String buildOverviewText(String dname,String ddesc) {
|
||||||
|
StringBuilder sb=new StringBuilder();
|
||||||
|
sb.append(UIEnv.getRsb().getString("ipv6addr")).append(": ").append(address.toCompressedString()).append('\n');
|
||||||
|
if(dname!=null&&!dname.isEmpty()) {
|
||||||
|
sb.append('\n').append(UIEnv.getRsb().getString("devicename")).append(": ").append(dname).append('\n');
|
||||||
|
}
|
||||||
|
if(ddesc!=null&&!ddesc.isEmpty()) {
|
||||||
|
sb.append('\n').append(UIEnv.getRsb().getString("devicedescription")).append(":\n").append(ddesc).append('\n');
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
public Icon getIcon() {
|
public Icon getIcon() {
|
||||||
return new ImageIcon(image);
|
return new ImageIcon(image);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,986 @@
|
|||||||
|
package org.kne.cloud.network.klalb.web;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import com.sun.net.httpserver.*;
|
||||||
|
import com.google.gson.*;
|
||||||
|
|
||||||
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
||||||
|
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
|
||||||
|
import org.kne.cloud.network.ipv6.RouteItem;
|
||||||
|
import org.kne.cloud.network.klalb.*;
|
||||||
|
import org.kne.cloud.network.monitor.LinkStatus;
|
||||||
|
import org.kne.cloud.network.srv6.KLALBNodeInformation;
|
||||||
|
import org.kne.cloud.network.srv6.KLALBRoutingProtocol;
|
||||||
|
import org.kne.cloud.network.srv6.KLALBRoutingProtocol.LinkDirection;
|
||||||
|
import org.kne.cloud.network.srv6.KLALBRoutingProtocolAPIClient;
|
||||||
|
import org.kne.cloud.network.srv6.NeighborInfo;
|
||||||
|
import org.kne.cloud.network.srv6.RouterInfo;
|
||||||
|
import org.kne.cloud.network.srv6.SRv6Router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KLALB Web Server providing REST API, SSE live event stream,
|
||||||
|
* and static dashboard hosting.
|
||||||
|
*/
|
||||||
|
public class KLALBWebServer {
|
||||||
|
private final KLALBProxySystem proxySystem;
|
||||||
|
private final MultiProtocolSocketAddress listen;
|
||||||
|
private HttpServer server;
|
||||||
|
private final Gson gson;
|
||||||
|
private final ScheduledExecutorService sseExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
|
||||||
|
Thread t = new Thread(r, "KLALB-Web-SSE");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
private final Set<HttpExchange> sseClients = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||||
|
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public KLALBWebServer(KLALBProxySystem proxySystem, int port) {
|
||||||
|
this(proxySystem, new MultiProtocolSocketAddress("http", "0.0.0.0", port));
|
||||||
|
}
|
||||||
|
|
||||||
|
public KLALBWebServer(KLALBProxySystem proxySystem, MultiProtocolSocketAddress listen) {
|
||||||
|
this.proxySystem = proxySystem;
|
||||||
|
this.listen = listen;
|
||||||
|
this.gson = proxySystem.getGson();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void start() throws IOException {
|
||||||
|
if (running.get()) return;
|
||||||
|
|
||||||
|
InetSocketAddress socketAddress = "0.0.0.0".equals(listen.getHost())
|
||||||
|
? new InetSocketAddress(listen.getPort()) : listen.getSocketAddress();
|
||||||
|
server = HttpServer.create(socketAddress, 0);
|
||||||
|
server.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
|
||||||
|
|
||||||
|
// API Contexts
|
||||||
|
server.createContext("/api/status", this::handleStatus);
|
||||||
|
server.createContext("/api/events", this::handleEvents);
|
||||||
|
server.createContext("/api/links", this::handleLinks);
|
||||||
|
server.createContext("/api/links/action", this::handleLinkAction);
|
||||||
|
server.createContext("/api/links/reconnect", this::handleReconnectAll);
|
||||||
|
server.createContext("/api/routing-table", this::handleRoutingTable);
|
||||||
|
server.createContext("/api/nodes", this::handleNodes);
|
||||||
|
server.createContext("/api/node-info", this::handleNodeInfo);
|
||||||
|
server.createContext("/api/config", this::handleConfig);
|
||||||
|
|
||||||
|
// Static Files / SPA Fallback Handler
|
||||||
|
server.createContext("/", this::handleStatic);
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
running.set(true);
|
||||||
|
startSseBroadcaster();
|
||||||
|
|
||||||
|
System.out.println("KLALB Web Dashboard started at " + listen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stop() {
|
||||||
|
if (!running.get()) return;
|
||||||
|
running.set(false);
|
||||||
|
sseExecutor.shutdownNow();
|
||||||
|
for (HttpExchange client : sseClients) {
|
||||||
|
try {
|
||||||
|
client.close();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
sseClients.clear();
|
||||||
|
if (server != null) {
|
||||||
|
server.stop(1);
|
||||||
|
server = null;
|
||||||
|
}
|
||||||
|
System.out.println("KLALB Web Dashboard stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return listen.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCorsHeaders(HttpExchange exchange) {
|
||||||
|
Headers headers = exchange.getResponseHeaders();
|
||||||
|
headers.set("Access-Control-Allow-Origin", "*");
|
||||||
|
headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
||||||
|
headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleCorsPreflight(HttpExchange exchange) throws IOException {
|
||||||
|
setCorsHeaders(exchange);
|
||||||
|
if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
exchange.sendResponseHeaders(204, -1);
|
||||||
|
exchange.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendJsonResponse(HttpExchange exchange, int statusCode, Object data) throws IOException {
|
||||||
|
setCorsHeaders(exchange);
|
||||||
|
String json;
|
||||||
|
if (data instanceof JsonElement) {
|
||||||
|
// gson-2.1 的 toJson(Object) 会按运行时类型 JsonObject 反射序列化出内部的 members 字段,
|
||||||
|
// 必须走 JsonElement 重载(或 toString)直接输出 JSON 树
|
||||||
|
json = ((JsonElement) data).toString();
|
||||||
|
} else {
|
||||||
|
json = gson.toJson(data);
|
||||||
|
}
|
||||||
|
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
|
||||||
|
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
|
||||||
|
exchange.sendResponseHeaders(statusCode, bytes.length);
|
||||||
|
try (OutputStream os = exchange.getResponseBody()) {
|
||||||
|
os.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendError(HttpExchange exchange, int statusCode, String message) throws IOException {
|
||||||
|
JsonObject error = new JsonObject();
|
||||||
|
error.addProperty("error", message);
|
||||||
|
sendJsonResponse(exchange, statusCode, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readRequestBody(HttpExchange exchange) throws IOException {
|
||||||
|
try (InputStream is = exchange.getRequestBody()) {
|
||||||
|
return new String(is.readAllBytes(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// API Handlers
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
|
private JsonObject getStatusJson() {
|
||||||
|
JsonObject root = new JsonObject();
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
if (kc == null) {
|
||||||
|
root.addProperty("status", "not_ready");
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.addProperty("version", CONST.klalbver);
|
||||||
|
root.addProperty("title", CONST.klalb);
|
||||||
|
|
||||||
|
IPv6AddressGroup self = kc.getSelf();
|
||||||
|
root.addProperty("address", self != null ? self.getAddress().toString() : "");
|
||||||
|
|
||||||
|
SRv6Router router = kc.getIpv6Router();
|
||||||
|
if (router != null && router.getKlalbRouteProtol() != null) {
|
||||||
|
root.addProperty("onlineDevices", router.getKlalbRouteProtol().getDevicesFound());
|
||||||
|
root.addProperty("deviceName", router.getDeviceName() != null ? router.getDeviceName() : "");
|
||||||
|
} else {
|
||||||
|
root.addProperty("onlineDevices", 0);
|
||||||
|
root.addProperty("deviceName", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
KLALBControllerConfigItem configItem = proxySystem.getControllerConfig();
|
||||||
|
if (configItem != null) {
|
||||||
|
root.addProperty("deviceDescription", configItem.getDeviceDescription() != null ? configItem.getDeviceDescription() : "");
|
||||||
|
root.addProperty("enableTUN", configItem.isEnableTUN());
|
||||||
|
root.addProperty("tunName", configItem.isEnableTUN() && configItem.getTUNName() != null ? configItem.getTUNName() : "");
|
||||||
|
root.addProperty("congestionAlgorithm", configItem.getCongestionAlgorithm() != null ? configItem.getCongestionAlgorithm() : "");
|
||||||
|
root.addProperty("performanceStrategy", configItem.getPerformanceStrategy() != null ? configItem.getPerformanceStrategy() : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clock
|
||||||
|
HighAccuracyClock hac = kc.getClock();
|
||||||
|
if (hac != null) {
|
||||||
|
long delta = hac.getFrequency() - 1000000000;
|
||||||
|
double ppm = delta / 1000.0;
|
||||||
|
root.addProperty("timeStr", hac.toString2());
|
||||||
|
root.addProperty("timePpm", ppm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metrics
|
||||||
|
JsonObject metrics = new JsonObject();
|
||||||
|
if (kc.getLinkMonitor() != null) {
|
||||||
|
metrics.addProperty("upSpeed", kc.getLinkMonitor().getOutSpeed());
|
||||||
|
metrics.addProperty("downSpeed", kc.getLinkMonitor().getInSpeed());
|
||||||
|
metrics.addProperty("upSpeedMax", kc.getLinkMonitor().getOutSpeedMax());
|
||||||
|
metrics.addProperty("downSpeedMax", kc.getLinkMonitor().getInSpeedMax());
|
||||||
|
metrics.addProperty("upPPS", kc.getLinkMonitor().getOutPPS());
|
||||||
|
metrics.addProperty("downPPS", kc.getLinkMonitor().getInPPS());
|
||||||
|
metrics.addProperty("upPPSMax", kc.getLinkMonitor().getOutPPSMax());
|
||||||
|
metrics.addProperty("downPPSMax", kc.getLinkMonitor().getInPPSMax());
|
||||||
|
metrics.addProperty("upTraffic", kc.getLinkMonitor().getOutTraffic());
|
||||||
|
metrics.addProperty("downTraffic", kc.getLinkMonitor().getInTraffic());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kc.getDatatMonitor() != null) {
|
||||||
|
metrics.addProperty("dataUpSpeed", kc.getDatatMonitor().getOutSpeed());
|
||||||
|
metrics.addProperty("dataDownSpeed", kc.getDatatMonitor().getInSpeed());
|
||||||
|
metrics.addProperty("dataUpPPS", kc.getDatatMonitor().getOutPPS());
|
||||||
|
metrics.addProperty("dataDownPPS", kc.getDatatMonitor().getInPPS());
|
||||||
|
metrics.addProperty("dataUpTraffic", kc.getDatatMonitor().getOutTraffic());
|
||||||
|
metrics.addProperty("dataDownTraffic", kc.getDatatMonitor().getInTraffic());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (router != null) {
|
||||||
|
metrics.addProperty("backplaneDelay", router.getBackplaneTime());
|
||||||
|
metrics.addProperty("backplanePPS", router.getBackplanePPS());
|
||||||
|
metrics.addProperty("backplanePPSMax", router.getBackplanePPSMax());
|
||||||
|
metrics.addProperty("backplaneECNRate", router.getECNRate());
|
||||||
|
metrics.addProperty("backplaneLossRate", router.getLossRate());
|
||||||
|
}
|
||||||
|
root.add("metrics", metrics);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleStatus(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendJsonResponse(exchange, 200, getStatusJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonArray getLinksJson() {
|
||||||
|
JsonArray array = new JsonArray();
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
if (kc == null) return array;
|
||||||
|
|
||||||
|
List<IPv6NetworkLink> linesList = kc.getLines();
|
||||||
|
synchronized (linesList) {
|
||||||
|
for (IPv6NetworkLink link : linesList) {
|
||||||
|
if (!(link instanceof KLALBRemoteLink)) continue;
|
||||||
|
KLALBRemoteLink remoteLink = (KLALBRemoteLink) link;
|
||||||
|
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
obj.addProperty("name", remoteLink.getName());
|
||||||
|
obj.addProperty("state", LinkStatus.stateToString(remoteLink.getState()));
|
||||||
|
obj.addProperty("stateCode", remoteLink.getState());
|
||||||
|
|
||||||
|
MultiProtocolSocketAddress mpsa = remoteLink.getSocketAddress();
|
||||||
|
obj.addProperty("socketAddress", mpsa != null ? mpsa.toString() : "");
|
||||||
|
|
||||||
|
IPv6AddressGroup vaddr = remoteLink.getRemoteVaddr();
|
||||||
|
obj.addProperty("vaddr", vaddr != null ? vaddr.getAddress().toString() : "");
|
||||||
|
|
||||||
|
if (remoteLink.getMonitor() != null) {
|
||||||
|
obj.addProperty("upSpeed", remoteLink.getMonitor().getOutSpeed());
|
||||||
|
obj.addProperty("downSpeed", remoteLink.getMonitor().getInSpeed());
|
||||||
|
obj.addProperty("upPPS", remoteLink.getMonitor().getOutPPS());
|
||||||
|
obj.addProperty("downPPS", remoteLink.getMonitor().getInPPS());
|
||||||
|
obj.addProperty("upTraffic", remoteLink.getMonitor().getOutTraffic());
|
||||||
|
obj.addProperty("downTraffic", remoteLink.getMonitor().getInTraffic());
|
||||||
|
obj.addProperty("upDelay", remoteLink.getMonitor().getOutDelay());
|
||||||
|
obj.addProperty("downDelay", remoteLink.getMonitor().getInDelay());
|
||||||
|
obj.addProperty("upDelayMin", remoteLink.getMonitor().getOutDelayMin());
|
||||||
|
obj.addProperty("downDelayMin", remoteLink.getMonitor().getInDelayMin());
|
||||||
|
obj.addProperty("upJitter", remoteLink.getMonitor().getOutJitter());
|
||||||
|
obj.addProperty("downJitter", remoteLink.getMonitor().getInJitter());
|
||||||
|
}
|
||||||
|
array.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleLinks(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
String method = exchange.getRequestMethod();
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
|
||||||
|
if ("GET".equalsIgnoreCase(method)) {
|
||||||
|
sendJsonResponse(exchange, 200, getLinksJson());
|
||||||
|
} else if ("POST".equalsIgnoreCase(method)) {
|
||||||
|
String body = readRequestBody(exchange);
|
||||||
|
try {
|
||||||
|
JsonObject req = new JsonParser().parse(body).getAsJsonObject();
|
||||||
|
String address = req.get("address").getAsString().trim();
|
||||||
|
if (address.isEmpty()) {
|
||||||
|
sendError(exchange, 400, "Address is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MultiProtocolSocketAddress mpsa = new MultiProtocolSocketAddress(address);
|
||||||
|
List<KLALBRemoteLink> added = kc.addRemoteLines(mpsa);
|
||||||
|
JsonObject resp = new JsonObject();
|
||||||
|
resp.addProperty("success", !added.isEmpty());
|
||||||
|
resp.addProperty("count", added.size());
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendError(exchange, 400, "Failed to add link: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else if ("DELETE".equalsIgnoreCase(method)) {
|
||||||
|
String query = exchange.getRequestURI().getQuery();
|
||||||
|
String address = null;
|
||||||
|
if (query != null && query.startsWith("address=")) {
|
||||||
|
address = URLDecoder.decode(query.substring(8), StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
String body = readRequestBody(exchange);
|
||||||
|
if (!body.isEmpty()) {
|
||||||
|
try {
|
||||||
|
JsonObject req = new JsonParser().parse(body).getAsJsonObject();
|
||||||
|
if (req.has("address")) {
|
||||||
|
address = req.get("address").getAsString();
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address == null || address.trim().isEmpty()) {
|
||||||
|
sendError(exchange, 400, "Address parameter required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
MultiProtocolSocketAddress mpsa = new MultiProtocolSocketAddress(address.trim());
|
||||||
|
List<KLALBRemoteLink> removed = kc.removeRemoteLines(mpsa);
|
||||||
|
JsonObject resp = new JsonObject();
|
||||||
|
resp.addProperty("success", !removed.isEmpty());
|
||||||
|
resp.addProperty("count", removed.size());
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendError(exchange, 400, "Failed to remove link: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleLinkAction(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"POST".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String body = readRequestBody(exchange);
|
||||||
|
try {
|
||||||
|
JsonObject req = new JsonParser().parse(body).getAsJsonObject();
|
||||||
|
String action = req.get("action").getAsString();
|
||||||
|
String address = req.has("address") ? req.get("address").getAsString() : null;
|
||||||
|
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
KLALBRemoteLink target = null;
|
||||||
|
if (address != null) {
|
||||||
|
for (IPv6NetworkLink link : kc.getLines()) {
|
||||||
|
if (link instanceof KLALBRemoteLink rl) {
|
||||||
|
if (rl.getName().equalsIgnoreCase(address) ||
|
||||||
|
(rl.getSocketAddress() != null && rl.getSocketAddress().toString().equalsIgnoreCase(address))) {
|
||||||
|
target = rl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject resp = new JsonObject();
|
||||||
|
if (target != null) {
|
||||||
|
switch (action) {
|
||||||
|
case "reconnect" -> {
|
||||||
|
target.reconnectImmediately();
|
||||||
|
resp.addProperty("success", true);
|
||||||
|
}
|
||||||
|
case "disconnect" -> {
|
||||||
|
target.dislink();
|
||||||
|
resp.addProperty("success", true);
|
||||||
|
}
|
||||||
|
case "remove" -> {
|
||||||
|
MultiProtocolSocketAddress mtar = target.getSocketAddress();
|
||||||
|
if (mtar != null) {
|
||||||
|
kc.removeRemoteLines(mtar);
|
||||||
|
} else {
|
||||||
|
target.close();
|
||||||
|
}
|
||||||
|
resp.addProperty("success", true);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
sendError(exchange, 400, "Unknown action: " + action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendError(exchange, 404, "Target link not found: " + address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendError(exchange, 400, "Failed to execute link action: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReconnectAll(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"POST".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
if (kc != null) {
|
||||||
|
kc.reconnectImmediately();
|
||||||
|
JsonObject resp = new JsonObject();
|
||||||
|
resp.addProperty("success", true);
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
} else {
|
||||||
|
sendError(exchange, 500, "Controller not ready");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRoutingTable(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
JsonArray routesArray = new JsonArray();
|
||||||
|
if (kc != null && kc.getIpv6Router() != null) {
|
||||||
|
List<RouteItem> list = new ArrayList<>(kc.getIpv6Router().getCurrentRouteTabel());
|
||||||
|
Collections.sort(list);
|
||||||
|
for (RouteItem item : list) {
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
obj.addProperty("destination", item.getDestination() != null ? item.getDestination().toString() : "");
|
||||||
|
obj.addProperty("protocol", item.getProto());
|
||||||
|
obj.addProperty("preference", item.getPre());
|
||||||
|
obj.addProperty("cost", item.getCost());
|
||||||
|
obj.addProperty("flag", item.getFlag());
|
||||||
|
obj.addProperty("nexthop", item.getNexthop() != null ? item.getNexthop().toString() : "");
|
||||||
|
obj.addProperty("interface", item.getDestlink() != null ? item.getDestlink().getName() : "");
|
||||||
|
routesArray.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendJsonResponse(exchange, 200, routesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
private KLALBRoutingProtocolAPIClient nodeInfoClient;
|
||||||
|
|
||||||
|
private synchronized KLALBRoutingProtocolAPIClient getNodeInfoClient(KLALBController kc) {
|
||||||
|
if (nodeInfoClient == null) {
|
||||||
|
nodeInfoClient = new KLALBRoutingProtocolAPIClient(kc.getIpv6Router().getKlalbRouteProtol());
|
||||||
|
}
|
||||||
|
return nodeInfoClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNodeInfo(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> params = parseQuery(exchange.getRequestURI().getRawQuery());
|
||||||
|
String addressStr = params.get("address");
|
||||||
|
if (addressStr == null || addressStr.trim().isEmpty()) {
|
||||||
|
sendError(exchange, 400, "address parameter is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
if (kc == null || kc.getIpv6Router() == null || kc.getIpv6Router().getKlalbRouteProtol() == null) {
|
||||||
|
sendError(exchange, 503, "Controller not ready");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPv6Address target;
|
||||||
|
try {
|
||||||
|
target = new IPv6Address((Inet6Address) InetAddress.getByName(addressStr.trim()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendError(exchange, 400, "Invalid IPv6 address: " + addressStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SRv6Router router = kc.getIpv6Router();
|
||||||
|
boolean isSelf = router.getLocator().getAddress().equals(target);
|
||||||
|
|
||||||
|
JsonObject resp = new JsonObject();
|
||||||
|
resp.addProperty("address", target.toString());
|
||||||
|
|
||||||
|
if (isSelf) {
|
||||||
|
// 本机:描述直接取本地控制器配置
|
||||||
|
KLALBControllerConfigItem cfg = proxySystem.getControllerConfig();
|
||||||
|
resp.addProperty("isSelf", true);
|
||||||
|
String dname = router.getDeviceName() != null ? router.getDeviceName()
|
||||||
|
: (cfg != null && cfg.getDeviceName() != null ? cfg.getDeviceName() : "");
|
||||||
|
resp.addProperty("deviceName", dname);
|
||||||
|
resp.addProperty("deviceDescription",
|
||||||
|
cfg != null && cfg.getDeviceDescription() != null ? cfg.getDeviceDescription() : "");
|
||||||
|
JsonArray lines = new JsonArray();
|
||||||
|
for (MultiProtocolSocketAddress mpsa : kc.getExternalEndpoints()) {
|
||||||
|
lines.add(new JsonPrimitive(mpsa.toString()));
|
||||||
|
}
|
||||||
|
resp.add("openLines", lines);
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 远端节点:经 SRv6 虚拟网络发送完整节点信息查询(异步回调,限时等待)
|
||||||
|
resp.addProperty("isSelf", false);
|
||||||
|
CompletableFuture<KLALBNodeInformation> future = new CompletableFuture<>();
|
||||||
|
try {
|
||||||
|
getNodeInfoClient(kc).requestNodeInfoFull(
|
||||||
|
new InetSocketAddress(target.toInet6Address(), KLALBRoutingProtocol.DEFAULT_PORT),
|
||||||
|
info -> future.complete(info));
|
||||||
|
|
||||||
|
KLALBNodeInformation info;
|
||||||
|
try {
|
||||||
|
info = future.get(3, TimeUnit.SECONDS);
|
||||||
|
} catch (TimeoutException te) {
|
||||||
|
info = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String dname = info != null && info.getDeviceName() != null && !info.getDeviceName().isEmpty()
|
||||||
|
? info.getDeviceName()
|
||||||
|
: router.getKlalbRouteProtol().getDeviceName(target);
|
||||||
|
resp.addProperty("deviceName", dname != null ? dname : "");
|
||||||
|
resp.addProperty("deviceDescription",
|
||||||
|
info != null && info.getDeviceDescription() != null ? info.getDeviceDescription() : "");
|
||||||
|
resp.addProperty("reachable", info != null);
|
||||||
|
JsonArray lines = new JsonArray();
|
||||||
|
if (info != null && info.getOpenLines() != null) {
|
||||||
|
for (MultiProtocolSocketAddress mpsa : info.getOpenLines()) {
|
||||||
|
lines.add(new JsonPrimitive(mpsa.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp.add("openLines", lines);
|
||||||
|
} catch (Exception e) {
|
||||||
|
resp.addProperty("deviceName", "");
|
||||||
|
resp.addProperty("deviceDescription", "");
|
||||||
|
resp.addProperty("reachable", false);
|
||||||
|
resp.add("openLines", new JsonArray());
|
||||||
|
}
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> parseQuery(String rawQuery) {
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
if (rawQuery == null || rawQuery.isEmpty()) return params;
|
||||||
|
for (String pair : rawQuery.split("&")) {
|
||||||
|
int idx = pair.indexOf('=');
|
||||||
|
if (idx <= 0) continue;
|
||||||
|
try {
|
||||||
|
params.put(URLDecoder.decode(pair.substring(0, idx), StandardCharsets.UTF_8),
|
||||||
|
URLDecoder.decode(pair.substring(idx + 1), StandardCharsets.UTF_8));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNodes(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KLALBController kc = proxySystem.getKlalbController();
|
||||||
|
JsonObject result = new JsonObject();
|
||||||
|
JsonArray nodesArray = new JsonArray();
|
||||||
|
JsonArray edgesArray = new JsonArray();
|
||||||
|
|
||||||
|
if (kc != null && kc.getIpv6Router() != null && kc.getIpv6Router().getKlalbRouteProtol() != null) {
|
||||||
|
KLALBRoutingProtocol rproto = kc.getIpv6Router().getKlalbRouteProtol();
|
||||||
|
Map<IPv6Address, Long> addrs = rproto.getAddresses();
|
||||||
|
IPv6Address selfAddr = kc.getIpv6Router().getLocator().getAddress();
|
||||||
|
|
||||||
|
if (addrs != null) {
|
||||||
|
for (IPv6Address addr : addrs.keySet()) {
|
||||||
|
JsonObject nodeObj = new JsonObject();
|
||||||
|
nodeObj.addProperty("id", addr.toString());
|
||||||
|
nodeObj.addProperty("address", addr.toString());
|
||||||
|
nodeObj.addProperty("compressedAddress", addr.toCompressedString());
|
||||||
|
nodeObj.addProperty("isSelf", addr.equals(selfAddr));
|
||||||
|
String dname = rproto.getDeviceName(addr);
|
||||||
|
nodeObj.addProperty("deviceName", dname != null ? dname : "");
|
||||||
|
nodesArray.add(nodeObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<IPv6Address, RouterInfo> netmap = rproto.getNetmap();
|
||||||
|
if (netmap != null) {
|
||||||
|
Set<String> seenEdges = new HashSet<>();
|
||||||
|
for (Map.Entry<IPv6Address, RouterInfo> entry : netmap.entrySet()) {
|
||||||
|
IPv6Address from = entry.getKey();
|
||||||
|
RouterInfo info = entry.getValue();
|
||||||
|
if (info != null && info.getNeighborAddresses() != null) {
|
||||||
|
for (NeighborInfo nb : info.getNeighborAddresses()) {
|
||||||
|
if (nb != null && nb.getLocator() != null) {
|
||||||
|
String to = nb.getLocator().getAddress().toString();
|
||||||
|
String edgeKey = from.toString().compareTo(to) < 0
|
||||||
|
? from.toString() + "->" + to
|
||||||
|
: to + "->" + from.toString();
|
||||||
|
if (!seenEdges.contains(edgeKey)) {
|
||||||
|
seenEdges.add(edgeKey);
|
||||||
|
JsonObject edgeObj = new JsonObject();
|
||||||
|
edgeObj.addProperty("source", from.toString());
|
||||||
|
edgeObj.addProperty("target", to);
|
||||||
|
edgeObj.addProperty("delay", nb.getUploadDelay());
|
||||||
|
edgeObj.addProperty("cost", nb.getUploadDelayMin());
|
||||||
|
edgesArray.add(edgeObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add("nodes", nodesArray);
|
||||||
|
result.add("edges", edgesArray);
|
||||||
|
sendJsonResponse(exchange, 200, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleConfig(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
String method = exchange.getRequestMethod();
|
||||||
|
|
||||||
|
if ("GET".equalsIgnoreCase(method)) {
|
||||||
|
KLALBControllerConfigItem config = proxySystem.getControllerConfig();
|
||||||
|
if (config != null) {
|
||||||
|
sendJsonResponse(exchange, 200, config);
|
||||||
|
} else {
|
||||||
|
sendError(exchange, 404, "Configuration not found");
|
||||||
|
}
|
||||||
|
} else if ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) {
|
||||||
|
String body = readRequestBody(exchange);
|
||||||
|
try {
|
||||||
|
JsonObject json = new JsonParser().parse(body).getAsJsonObject();
|
||||||
|
KLALBControllerConfigItem current = proxySystem.getControllerConfig();
|
||||||
|
if (current != null) {
|
||||||
|
if (json.has("deviceName") && !json.get("deviceName").isJsonNull()) {
|
||||||
|
current.setDeviceName(json.get("deviceName").getAsString());
|
||||||
|
} else if (json.has("DeviceName") && !json.get("DeviceName").isJsonNull()) {
|
||||||
|
current.setDeviceName(json.get("DeviceName").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("deviceDescription") && !json.get("deviceDescription").isJsonNull()) {
|
||||||
|
current.setDeviceDescription(json.get("deviceDescription").getAsString());
|
||||||
|
} else if (json.has("DeviceDescription") && !json.get("DeviceDescription").isJsonNull()) {
|
||||||
|
current.setDeviceDescription(json.get("DeviceDescription").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("language") && !json.get("language").isJsonNull()) {
|
||||||
|
current.setLanguage(json.get("language").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("virtualAddress") && !json.get("virtualAddress").isJsonNull()) {
|
||||||
|
current.setVirtualAddress(json.get("virtualAddress").getAsString());
|
||||||
|
} else if (json.has("VirtualAddress") && !json.get("VirtualAddress").isJsonNull()) {
|
||||||
|
current.setVirtualAddress(json.get("VirtualAddress").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("virtualASN") && !json.get("virtualASN").isJsonNull()) {
|
||||||
|
current.setVirtualASN(json.get("virtualASN").getAsLong());
|
||||||
|
} else if (json.has("VirtualASN") && !json.get("VirtualASN").isJsonNull()) {
|
||||||
|
current.setVirtualASN(json.get("VirtualASN").getAsLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("virtualSocketName") && !json.get("virtualSocketName").isJsonNull()) {
|
||||||
|
current.setVirtualSocketName(json.get("virtualSocketName").getAsString());
|
||||||
|
} else if (json.has("VirtualSocketName") && !json.get("VirtualSocketName").isJsonNull()) {
|
||||||
|
current.setVirtualSocketName(json.get("VirtualSocketName").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("enableTUN")) {
|
||||||
|
current.setEnableTUN(json.get("enableTUN").getAsBoolean());
|
||||||
|
} else if (json.has("EnableTUN")) {
|
||||||
|
current.setEnableTUN(json.get("EnableTUN").getAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("tunName") && !json.get("tunName").isJsonNull()) {
|
||||||
|
current.setTUNName(json.get("tunName").getAsString());
|
||||||
|
} else if (json.has("TUNName") && !json.get("TUNName").isJsonNull()) {
|
||||||
|
current.setTUNName(json.get("TUNName").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("webUI")) {
|
||||||
|
current.setWebUI(json.get("webUI").getAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("webListen") && !json.get("webListen").isJsonNull()) {
|
||||||
|
current.setWebListen(new MultiProtocolSocketAddress(json.get("webListen").getAsString()));
|
||||||
|
} else if (json.has("webPort")) {
|
||||||
|
current.setWebListen(new MultiProtocolSocketAddress("http", "0.0.0.0", json.get("webPort").getAsInt()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("nogui")) {
|
||||||
|
current.setNogui(json.get("nogui").getAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("tcpListen") && !json.get("tcpListen").isJsonNull()) {
|
||||||
|
current.setTCPListen(new MultiProtocolSocketAddress(json.get("tcpListen").getAsString()));
|
||||||
|
} else if (json.has("TCPListen") && !json.get("TCPListen").isJsonNull()) {
|
||||||
|
current.setTCPListen(new MultiProtocolSocketAddress(json.get("TCPListen").getAsString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("udpListen") && !json.get("udpListen").isJsonNull()) {
|
||||||
|
current.setUDPListen(new MultiProtocolSocketAddress(json.get("udpListen").getAsString()));
|
||||||
|
} else if (json.has("UDPListen") && !json.get("UDPListen").isJsonNull()) {
|
||||||
|
current.setUDPListen(new MultiProtocolSocketAddress(json.get("UDPListen").getAsString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("externalEndpoints") || json.has("ExternalEndpoints") || json.has("openConnections") || json.has("OpenConnections") || json.has("lineTable") || json.has("LineTable")) {
|
||||||
|
JsonArray arr = json.has("externalEndpoints") ? json.getAsJsonArray("externalEndpoints")
|
||||||
|
: json.has("ExternalEndpoints") ? json.getAsJsonArray("ExternalEndpoints")
|
||||||
|
: json.has("openConnections") ? json.getAsJsonArray("openConnections")
|
||||||
|
: json.has("OpenConnections") ? json.getAsJsonArray("OpenConnections")
|
||||||
|
: json.has("lineTable") ? json.getAsJsonArray("lineTable") : json.getAsJsonArray("LineTable");
|
||||||
|
List<MultiProtocolSocketAddress> list = new ArrayList<>();
|
||||||
|
for (JsonElement el : arr) {
|
||||||
|
if (el.isJsonPrimitive()) {
|
||||||
|
list.add(new MultiProtocolSocketAddress(el.getAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.setExternalEndpoints(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("autoConnections") || json.has("AutoConnections") || json.has("connectLineTable") || json.has("ConnectLineTable")) {
|
||||||
|
JsonArray arr = json.has("autoConnections") ? json.getAsJsonArray("autoConnections")
|
||||||
|
: json.has("AutoConnections") ? json.getAsJsonArray("AutoConnections")
|
||||||
|
: json.has("connectLineTable") ? json.getAsJsonArray("connectLineTable") : json.getAsJsonArray("ConnectLineTable");
|
||||||
|
List<MultiProtocolSocketAddress> list = new ArrayList<>();
|
||||||
|
for (JsonElement el : arr) {
|
||||||
|
if (el.isJsonPrimitive()) {
|
||||||
|
list.add(new MultiProtocolSocketAddress(el.getAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.setAutoConnections(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("ntpServers") || json.has("NtpServers") || json.has("ntpServerTable")) {
|
||||||
|
JsonArray arr = json.has("ntpServers") ? json.getAsJsonArray("ntpServers")
|
||||||
|
: json.has("NtpServers") ? json.getAsJsonArray("NtpServers")
|
||||||
|
: json.getAsJsonArray("ntpServerTable");
|
||||||
|
List<MultiProtocolSocketAddress> list = new ArrayList<>();
|
||||||
|
for (JsonElement el : arr) {
|
||||||
|
if (el.isJsonPrimitive()) {
|
||||||
|
list.add(new MultiProtocolSocketAddress(el.getAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.setNtpServers(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("dns") || json.has("DNS")) {
|
||||||
|
JsonArray arr = json.has("dns") ? json.getAsJsonArray("dns") : json.getAsJsonArray("DNS");
|
||||||
|
List<InetAddress> list = new ArrayList<>();
|
||||||
|
for (JsonElement el : arr) {
|
||||||
|
if (el.isJsonPrimitive()) {
|
||||||
|
try {
|
||||||
|
list.add(InetAddress.getByName(el.getAsString()));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.setDNS(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("extraRoutes") || json.has("ExtraRoutes")) {
|
||||||
|
JsonArray arr = json.has("extraRoutes") ? json.getAsJsonArray("extraRoutes") : json.getAsJsonArray("ExtraRoutes");
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (JsonElement el : arr) {
|
||||||
|
if (el.isJsonPrimitive()) {
|
||||||
|
list.add(el.getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.setExtraRoutes(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("networkInterfaceExcepts") || json.has("NetworkInterfaceExcepts")) {
|
||||||
|
JsonArray arr = json.has("networkInterfaceExcepts") ? json.getAsJsonArray("networkInterfaceExcepts") : json.getAsJsonArray("NetworkInterfaceExcepts");
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (JsonElement el : arr) {
|
||||||
|
if (el.isJsonPrimitive()) {
|
||||||
|
list.add(el.getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current.setNetworkInterfaceExcepts(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("congestionAlgorithm") && !json.get("congestionAlgorithm").isJsonNull()) {
|
||||||
|
current.setCongestionAlgorithm(json.get("congestionAlgorithm").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("performanceStrategy") && !json.get("performanceStrategy").isJsonNull()) {
|
||||||
|
current.setPerformanceStrategy(json.get("performanceStrategy").getAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("linkConnectionsCount")) {
|
||||||
|
current.setLinkConnectionsCount(json.get("linkConnectionsCount").getAsInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("burstLimit")) {
|
||||||
|
current.setBurstLimit(json.get("burstLimit").getAsDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("delayUpperBound")) {
|
||||||
|
current.setDelayUpperBound(json.get("delayUpperBound").getAsDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("delayLowerBound")) {
|
||||||
|
current.setDelayLowerBound(json.get("delayLowerBound").getAsDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("nagleDelayTime")) {
|
||||||
|
current.setNagleDelayTime(json.get("nagleDelayTime").getAsLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("linkNagleDelayTime")) {
|
||||||
|
current.setLinkNagleDelayTime(json.get("linkNagleDelayTime").getAsLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("denyExternalEndpointQuery")) {
|
||||||
|
current.setDenyExternalEndpointQuery(json.get("denyExternalEndpointQuery").getAsBoolean());
|
||||||
|
} else if (json.has("denyConnectionQuery")) {
|
||||||
|
current.setDenyExternalEndpointQuery(json.get("denyConnectionQuery").getAsBoolean());
|
||||||
|
} else if (json.has("denyLineTableQuery")) {
|
||||||
|
current.setDenyExternalEndpointQuery(json.get("denyLineTableQuery").getAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("denyExternalEndpointBroadcast")) {
|
||||||
|
current.setDenyExternalEndpointBroadcast(json.get("denyExternalEndpointBroadcast").getAsBoolean());
|
||||||
|
} else if (json.has("denyConnectionBroadcast")) {
|
||||||
|
current.setDenyExternalEndpointBroadcast(json.get("denyConnectionBroadcast").getAsBoolean());
|
||||||
|
} else if (json.has("denyLineTableBroadcast")) {
|
||||||
|
current.setDenyExternalEndpointBroadcast(json.get("denyLineTableBroadcast").getAsBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger GUI save consumer or save directly
|
||||||
|
if (proxySystem.getKLALBGUI() != null && proxySystem.getKLALBGUI().getSaveComsumer() != null) {
|
||||||
|
proxySystem.getKLALBGUI().getSaveComsumer().accept(proxySystem.getConfig());
|
||||||
|
} else {
|
||||||
|
proxySystem.saveConfigToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject resp = new JsonObject();
|
||||||
|
resp.addProperty("success", true);
|
||||||
|
resp.addProperty("message", "Configuration updated successfully");
|
||||||
|
sendJsonResponse(exchange, 200, resp);
|
||||||
|
} else {
|
||||||
|
sendError(exchange, 500, "Current configuration is null");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendError(exchange, 400, "Failed to update configuration: " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// SSE Handler & Broadcaster
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
|
private void handleEvents(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
if (!"GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
|
sendError(exchange, 405, "Method not allowed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Headers headers = exchange.getResponseHeaders();
|
||||||
|
headers.set("Content-Type", "text/event-stream; charset=utf-8");
|
||||||
|
headers.set("Cache-Control", "no-cache, no-transform");
|
||||||
|
headers.set("Connection", "keep-alive");
|
||||||
|
headers.set("Access-Control-Allow-Origin", "*");
|
||||||
|
|
||||||
|
exchange.sendResponseHeaders(200, 0);
|
||||||
|
sseClients.add(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startSseBroadcaster() {
|
||||||
|
sseExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
if (sseClients.isEmpty()) return;
|
||||||
|
|
||||||
|
JsonObject eventData = new JsonObject();
|
||||||
|
eventData.add("status", getStatusJson());
|
||||||
|
eventData.add("links", getLinksJson());
|
||||||
|
String eventStr = "data: " + eventData.toString() + "\n\n";
|
||||||
|
byte[] bytes = eventStr.getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
Iterator<HttpExchange> it = sseClients.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
HttpExchange ex = it.next();
|
||||||
|
try {
|
||||||
|
OutputStream os = ex.getResponseBody();
|
||||||
|
os.write(bytes);
|
||||||
|
os.flush();
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
ex.close();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 200, 200, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
// Static Resource / SPA Handler
|
||||||
|
// -------------------------------------------------------------
|
||||||
|
|
||||||
|
private void handleStatic(HttpExchange exchange) throws IOException {
|
||||||
|
if (handleCorsPreflight(exchange)) return;
|
||||||
|
|
||||||
|
String path = exchange.getRequestURI().getPath();
|
||||||
|
if (path.startsWith("/api/")) {
|
||||||
|
sendError(exchange, 404, "API endpoint not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for dashboard/dist
|
||||||
|
File distDir = new File("dashboard/dist");
|
||||||
|
File targetFile = null;
|
||||||
|
|
||||||
|
if (distDir.exists() && distDir.isDirectory()) {
|
||||||
|
String relPath = path.equals("/") ? "index.html" : path.substring(1);
|
||||||
|
targetFile = new File(distDir, relPath);
|
||||||
|
if (!targetFile.exists() || targetFile.isDirectory()) {
|
||||||
|
targetFile = new File(distDir, "index.html");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetFile != null && targetFile.exists() && targetFile.isFile()) {
|
||||||
|
String mime = getMimeType(targetFile.getName());
|
||||||
|
byte[] content = Files.readAllBytes(targetFile.toPath());
|
||||||
|
setCorsHeaders(exchange);
|
||||||
|
exchange.getResponseHeaders().set("Content-Type", mime);
|
||||||
|
exchange.sendResponseHeaders(200, content.length);
|
||||||
|
try (OutputStream os = exchange.getResponseBody()) {
|
||||||
|
os.write(content);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback welcome message if frontend not built yet
|
||||||
|
String html = "<!DOCTYPE html><html><head><meta charset='utf-8'><title>KLALB Web Dashboard</title>" +
|
||||||
|
"<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#09090b;color:#fafafa}" +
|
||||||
|
".card{background:#18181b;padding:2rem;border-radius:0.75rem;border:1px solid #27272a;max-width:480px;text-align:center}" +
|
||||||
|
"h1{margin:0 0 0.5rem;font-size:1.5rem}p{color:#a1a1aa;margin:0 0 1rem;font-size:0.875rem}code{background:#27272a;padding:0.2rem 0.4rem;border-radius:0.25rem}</style></head>" +
|
||||||
|
"<body><div class='card'><h1>KLALB Web Dashboard API Active</h1>" +
|
||||||
|
"<p>The backend API is ready. Start the frontend dev server or build the dashboard: <br><code>cd dashboard && pnpm build</code></p>" +
|
||||||
|
"<p><a href='/api/status' style='color:#38bdf8'>View /api/status</a></p></div></body></html>";
|
||||||
|
byte[] bytes = html.getBytes(StandardCharsets.UTF_8);
|
||||||
|
setCorsHeaders(exchange);
|
||||||
|
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");
|
||||||
|
exchange.sendResponseHeaders(200, bytes.length);
|
||||||
|
try (OutputStream os = exchange.getResponseBody()) {
|
||||||
|
os.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMimeType(String filename) {
|
||||||
|
String lower = filename.toLowerCase();
|
||||||
|
if (lower.endsWith(".html")) return "text/html; charset=utf-8";
|
||||||
|
if (lower.endsWith(".js") || lower.endsWith(".mjs")) return "application/javascript; charset=utf-8";
|
||||||
|
if (lower.endsWith(".css")) return "text/css; charset=utf-8";
|
||||||
|
if (lower.endsWith(".json")) return "application/json; charset=utf-8";
|
||||||
|
if (lower.endsWith(".svg")) return "image/svg+xml";
|
||||||
|
if (lower.endsWith(".png")) return "image/png";
|
||||||
|
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
||||||
|
if (lower.endsWith(".ico")) return "image/x-icon";
|
||||||
|
if (lower.endsWith(".woff2")) return "font/woff2";
|
||||||
|
if (lower.endsWith(".woff")) return "font/woff";
|
||||||
|
if (lower.endsWith(".ttf")) return "font/ttf";
|
||||||
|
return "application/octet-stream";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,20 +3,18 @@ package org.kne.cloud.network.kltp;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.BindException;
|
import java.net.BindException;
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.WritableByteChannel;
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
|
||||||
|
import org.kne.cloud.network.klalb.KLALBScheduler;
|
||||||
import org.kne.concurrent.*;
|
import org.kne.concurrent.*;
|
||||||
import org.kne.cloud.network.NetworkPacket;
|
|
||||||
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
||||||
import org.kne.cloud.network.congestion.DCTCP2CongestionAlgorithm;
|
|
||||||
import org.kne.cloud.network.congestion.DCTCPCongestionAlgorithm;
|
import org.kne.cloud.network.congestion.DCTCPCongestionAlgorithm;
|
||||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Address;
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
||||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||||
import org.kne.cloud.network.klalb.DATATPacket;
|
|
||||||
import org.kne.cloud.network.klalb.KLALBController;
|
import org.kne.cloud.network.klalb.KLALBController;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -238,23 +236,27 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if(sendMap.isClosed())
|
if(sendMap.isClosed()) {
|
||||||
tt.cancel(false);
|
tt.cancel(false);
|
||||||
try {
|
}else if(!sendMap.isCongestion()){
|
||||||
if(olock!=null)
|
|
||||||
olock.lock();
|
|
||||||
try {
|
try {
|
||||||
flush0();
|
if (olock != null)
|
||||||
}finally {
|
olock.lock();
|
||||||
if(olock!=null)
|
try {
|
||||||
olock.unlock();
|
if(!sendMap.isCongestion()) {
|
||||||
|
flush0();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (olock != null)
|
||||||
|
olock.unlock();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ioe.set(e);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
ioe.set(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tt=controller.getScheduleTimer().scheduleAtFixedRate (r, delaytime, delaytime,TimeUnit.NANOSECONDS);
|
tt= KLALBScheduler.getScheduler().scheduleWithFixedDelay(r, delaytime, delaytime,TimeUnit.NANOSECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
IOException ioex=ioe.get();
|
IOException ioex=ioe.get();
|
||||||
@@ -271,7 +273,7 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
|||||||
|
|
||||||
sendMap.waitForAvaliable();
|
sendMap.waitForAvaliable();
|
||||||
|
|
||||||
controller.getIpv6Router().runPacketSendTask(()->{
|
controller.getIpv6Router().enqueuePacketSendTask(()->{
|
||||||
pack.getKLTPData().flip();
|
pack.getKLTPData().flip();
|
||||||
pack.incSendCounter();
|
pack.incSendCounter();
|
||||||
sendMap.put(pack.getSequence(),pack);
|
sendMap.put(pack.getSequence(),pack);
|
||||||
@@ -353,7 +355,7 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
|
|||||||
KLTPPacket kltp=(KLTPPacket) u.getPayload();
|
KLTPPacket kltp=(KLTPPacket) u.getPayload();
|
||||||
switch(kltp.getType()) {
|
switch(kltp.getType()) {
|
||||||
case KLTPPacket.KLTP_TYPE_ACK:
|
case KLTPPacket.KLTP_TYPE_ACK:
|
||||||
sendMap.ack(kltp.getSequence(), kltp.isCE());
|
sendMap.ack(kltp.getSequence(),0, kltp.isCE());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
return clock;
|
return clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
public ArrayListTimestampMonitor(HighAccuracyClock clock, String name, int maxRetry, long cleanupThreshold) {
|
||||||
super();
|
super();
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -67,6 +67,11 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length);
|
return recordPacket(key,clock.getCurrentTimeNanos(),count,length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean recordPacket(K key, int count, int length, long delay, long delayMin) {
|
||||||
|
return recordPacket(key, clock.getCurrentTimeNanos(),count, length, delay,delayMin);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean recordPacket(K key,int count, int length, long delay) {
|
public boolean recordPacket(K key,int count, int length, long delay) {
|
||||||
return recordPacket(key, clock.getCurrentTimeNanos(),count, length, delay);
|
return recordPacket(key, clock.getCurrentTimeNanos(),count, length, delay);
|
||||||
}
|
}
|
||||||
@@ -75,17 +80,22 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
return recordPacket(key, timestamp,count, length, Long.MAX_VALUE / 1024);
|
return recordPacket(key, timestamp,count, length, Long.MAX_VALUE / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean recordPacket(K key, Long128 timestamp, int count, int length, long dsndDelay) {
|
||||||
|
return recordPacket(key, timestamp, count, length, dsndDelay,dsndDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记录数据包 - 使用插入排序保持列表有序,添加时间戳验证
|
* 记录数据包 - 使用插入排序保持列表有序,添加时间戳验证
|
||||||
*/
|
*/
|
||||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay) {
|
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay, long dsndDelayMin) {
|
||||||
// 验证时间戳的合理性
|
// 验证时间戳的合理性
|
||||||
validateTimestamp(timestamp);
|
validateTimestamp(timestamp);
|
||||||
|
|
||||||
// 快速路径:尝试sequence=0
|
// 快速路径:尝试sequence=0
|
||||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey, timestamp,count, length, delay);
|
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey, timestamp,count, length, delay,dsndDelayMin);
|
||||||
autoCleanup(cleanupThreshold);
|
autoCleanup(cleanupThreshold);
|
||||||
|
|
||||||
rwLock.writeLock().lock();
|
rwLock.writeLock().lock();
|
||||||
@@ -461,6 +471,48 @@ public class ArrayListTimestampMonitor<K> implements TimestampMonitor<K> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从已排序的列表中计算数据量 - 优化版本,只需要startTime
|
||||||
|
*/
|
||||||
|
private long calculateMinDelayFromSortedList(List<TimestampMonitorValue> sortedList, Long128 startTime) {
|
||||||
|
if (sortedList.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用二分查找找到第一个 >= startTime 的元素位置
|
||||||
|
int startIndex = findFirstValidIndexFromSorted(sortedList, startTime);
|
||||||
|
|
||||||
|
if (startIndex >= sortedList.size()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算从startIndex到末尾的所有数据量(因为数据包不会来自未来)
|
||||||
|
long sum = Long.MAX_VALUE/1024;
|
||||||
|
for (int i = startIndex; i < sortedList.size(); i++) {
|
||||||
|
sum =Math.min(sortedList.get(i).getDelayMin(),sum) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long calculateMinDelay(long timeWindowNs){
|
||||||
|
return calculateMinDelay(clock.getCurrentTimeNanos(),timeWindowNs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long calculateMinDelay(Long128 currentTime, long timeWindowNs){
|
||||||
|
Long128 startTime = currentTime.subtract(Long128.valueOf(timeWindowNs));
|
||||||
|
rwLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
return calculateMinDelayFromSortedList(entries, startTime);
|
||||||
|
} finally {
|
||||||
|
rwLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private volatile TimestampMonitorValue recent=null;
|
private volatile TimestampMonitorValue recent=null;
|
||||||
@Override
|
@Override
|
||||||
public TimestampMonitorValue getRecentDelayEntry() {
|
public TimestampMonitorValue getRecentDelayEntry() {
|
||||||
|
|||||||
@@ -76,15 +76,22 @@ private String name;
|
|||||||
return recordPacket(key,clock.getCurrentTimeNanos(),count,length,delay);
|
return recordPacket(key,clock.getCurrentTimeNanos(),count,length,delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean recordPacket(K key, int count, int length, long delay, long delayMin) {
|
||||||
|
return recordPacket(key,clock.getCurrentTimeNanos(),count,length,delay,delayMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay) {
|
||||||
|
return recordPacket(key,timestamp,count,length,delay,delay);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 超高性能记录数据包 - 针对路由器优化
|
* 超高性能记录数据包 - 针对路由器优化
|
||||||
*/
|
*/
|
||||||
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay) {
|
public boolean recordPacket(K key, Long128 timestamp,int count, int length, long delay,long delayMin) {
|
||||||
autoCleanup(cleanupThreshold);
|
autoCleanup(cleanupThreshold);
|
||||||
// 快速路径:尝试sequence=0
|
// 快速路径:尝试sequence=0
|
||||||
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
TimestampMonitorKey<K> monitorKey = new TimestampMonitorKey<>(key, 0);
|
||||||
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey,timestamp, count,length,delay);
|
TimestampMonitorValue monitorValue = new TimestampMonitorValue(monitorKey,timestamp, count,length,delay,delayMin);
|
||||||
|
|
||||||
if (entries.putIfAbsent(monitorKey, monitorValue) == null) {
|
if (entries.putIfAbsent(monitorKey, monitorValue) == null) {
|
||||||
totalDataSize.add(length);
|
totalDataSize.add(length);
|
||||||
@@ -304,7 +311,18 @@ private String name;
|
|||||||
// TODO 自动生成的方法存根
|
// TODO 自动生成的方法存根
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
|
@Override
|
||||||
|
public long calculateMinDelay(long timeWindowNs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long calculateMinDelay(Long128 currentTime, long timeWindowNs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TimestampMonitorValue getRecentDelayEntry() {
|
public TimestampMonitorValue getRecentDelayEntry() {
|
||||||
// TODO 自动生成的方法存根
|
// TODO 自动生成的方法存根
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -19,27 +19,17 @@ public class SpeedAndTrafficAndDelayMonitorDataImpl extends SpeedAndTrafficMonit
|
|||||||
upSampler.update();
|
upSampler.update();
|
||||||
downSampler.update();
|
downSampler.update();
|
||||||
if(upSampler.getSnapshotPacketCount()>0&&upSampler.getSnapshotTotalDelay()>0) {
|
if(upSampler.getSnapshotPacketCount()>0&&upSampler.getSnapshotTotalDelay()>0) {
|
||||||
getUploadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, upSampler.getAvgDelayNanos());
|
getUploadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, upSampler.getAvgDelayNanos(),upSampler.getMinDelayNanos());
|
||||||
}
|
}
|
||||||
if(downSampler.getSnapshotPacketCount()>0&&downSampler.getSnapshotTotalDelay()>0) {
|
if(downSampler.getSnapshotPacketCount()>0&&downSampler.getSnapshotTotalDelay()>0) {
|
||||||
getDownloadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, downSampler.getAvgDelayNanos());
|
getDownloadBandwidth(). recordPacket(KLALBUtils.createGlobalUUID(),0, 0, downSampler.getAvgDelayNanos(),downSampler.getMinDelayNanos());
|
||||||
}
|
}
|
||||||
|
|
||||||
long time=System.nanoTime();
|
long time=System.nanoTime();
|
||||||
if(time-stime>timewindowmax) {
|
if(time-stime>timewindowmax) {
|
||||||
|
outDelayMin=getUploadBandwidth().calculateMinDelay(super.getTimeWindowMax());
|
||||||
|
inDelayMin=getDownloadBandwidth().calculateMinDelay(super.getTimeWindowMax());
|
||||||
stime=time;
|
stime=time;
|
||||||
long idelay=getInDelay();
|
|
||||||
if(inDelayMin==Long.MAX_VALUE||idelay<=inDelayMin) {
|
|
||||||
inDelayMin=idelay;
|
|
||||||
}else{
|
|
||||||
inDelayMin=(inDelayMin*99+idelay)/100;
|
|
||||||
}
|
|
||||||
long odelay=getOutDelay();
|
|
||||||
if(outDelayMin==Long.MAX_VALUE||odelay<=outDelayMin) {
|
|
||||||
outDelayMin=odelay;
|
|
||||||
}else{
|
|
||||||
outDelayMin=(outDelayMin*99+odelay)/100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements S
|
|||||||
private TimestampMonitor<UUID>uploadBandwidth;
|
private TimestampMonitor<UUID>uploadBandwidth;
|
||||||
private TimestampMonitor<UUID>downloadBandwidth;
|
private TimestampMonitor<UUID>downloadBandwidth;
|
||||||
private long timewindow=1000000000L;
|
private long timewindow=1000000000L;
|
||||||
private long timewindowmax=1000000000L;
|
private long timewindowmax=30000000000L;
|
||||||
private BandwidthSampler upSampler=new BandwidthSampler();
|
private BandwidthSampler upSampler=new BandwidthSampler();
|
||||||
private BandwidthSampler downSampler=new BandwidthSampler();
|
private BandwidthSampler downSampler=new BandwidthSampler();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final long TIME_WINDOW=2000000000L;
|
private final long TIME_WINDOW=50000000000L;
|
||||||
public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
|
public SpeedAndTrafficMonitorDataImpl(HighAccuracyClock clock) {
|
||||||
super();
|
super();
|
||||||
this.clock=clock;
|
this.clock=clock;
|
||||||
@@ -177,32 +177,39 @@ public class SpeedAndTrafficMonitorDataImpl extends MonitorDataImpl implements S
|
|||||||
inPPSEvaluator.markDirty();
|
inPPSEvaluator.markDirty();
|
||||||
}
|
}
|
||||||
long time=System.nanoTime();
|
long time=System.nanoTime();
|
||||||
if(time-stime>timewindowmax) {
|
if(time-stime>timewindow) {
|
||||||
stime=time;
|
stime=time;
|
||||||
long os=uploadBandwidth.calculateBandwidth(timewindowmax);
|
long os=uploadBandwidth.calculateBandwidth(timewindowmax);
|
||||||
long is=downloadBandwidth.calculateBandwidth(timewindowmax);
|
long is=downloadBandwidth.calculateBandwidth(timewindowmax);
|
||||||
long op=uploadBandwidth.calculatePacketRate(timewindowmax);
|
long op=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||||
long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
|
long ip=uploadBandwidth.calculatePacketRate(timewindowmax);
|
||||||
if(os>outSpeeedMax) {
|
if(os>outSpeeedMax) {
|
||||||
outSpeeedMax=(outSpeeedMax+os)/2;
|
outSpeeedMax=os;
|
||||||
}else {
|
}else {
|
||||||
outSpeeedMax=(outSpeeedMax*999+os)/1000;
|
outSpeeedMax=(outSpeeedMax*999+os)/1000;
|
||||||
}
|
}
|
||||||
if(is>inSpeedMax) {
|
if(is>inSpeedMax) {
|
||||||
inSpeedMax=(inSpeedMax+is)/2;
|
inSpeedMax=is;
|
||||||
}else {
|
}else {
|
||||||
inSpeedMax=(inSpeedMax*999+is)/1000;
|
inSpeedMax=(inSpeedMax*999+is)/1000;
|
||||||
}
|
}
|
||||||
if(op>outPPSMax) {
|
if(op>outPPSMax) {
|
||||||
outPPSMax=(outPPSMax+op)/2;
|
outPPSMax=op;
|
||||||
}else {
|
}else {
|
||||||
outPPSMax=(outPPSMax*999+op)/1000;
|
outPPSMax=(outPPSMax*999+op)/1000;
|
||||||
}
|
}
|
||||||
if(ip>inPPSMax) {
|
if(ip>inPPSMax) {
|
||||||
inPPSMax=(inPPSMax+ip)/2;
|
inPPSMax=ip;
|
||||||
}else {
|
}else {
|
||||||
inPPSMax=(inPPSMax*999+ip)/1000;
|
inPPSMax=(inPPSMax*999+ip)/1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected long getTimeWindow() {
|
||||||
|
return timewindow;
|
||||||
|
}
|
||||||
|
protected long getTimeWindowMax() {
|
||||||
|
return timewindowmax;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.kne.cloud.network.monitor;
|
package org.kne.cloud.network.monitor;
|
||||||
|
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
import org.kne.cloud.network.ipv6.PacketID;
|
|
||||||
import org.kne.math.Long128;
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,6 +36,9 @@ public interface TimestampMonitor<K> {
|
|||||||
*/
|
*/
|
||||||
boolean recordPacket(K key,int count, int length);
|
boolean recordPacket(K key,int count, int length);
|
||||||
|
|
||||||
|
boolean recordPacket(K key, int count,int length, long dsndDelay);
|
||||||
|
|
||||||
|
boolean recordPacket(K key, int count, int length, long avgDelayNanos, long minDelayNanos);
|
||||||
/**
|
/**
|
||||||
* 记录数据包(使用指定时间戳)
|
* 记录数据包(使用指定时间戳)
|
||||||
* @param key 数据包标识
|
* @param key 数据包标识
|
||||||
@@ -49,7 +51,9 @@ public interface TimestampMonitor<K> {
|
|||||||
|
|
||||||
boolean recordPacket(K key, Long128 timestamp, int count,int length, long dsndDelay);
|
boolean recordPacket(K key, Long128 timestamp, int count,int length, long dsndDelay);
|
||||||
|
|
||||||
boolean recordPacket(K key, int count,int length, long dsndDelay);
|
|
||||||
|
|
||||||
|
boolean recordPacket(K key, Long128 timestamp, int count,int length, long dsndDelay,long dsndDelayMin);
|
||||||
|
|
||||||
// ==================== 清理维护方法 ====================
|
// ==================== 清理维护方法 ====================
|
||||||
|
|
||||||
@@ -146,7 +150,11 @@ public interface TimestampMonitor<K> {
|
|||||||
long getRecentDelay();
|
long getRecentDelay();
|
||||||
|
|
||||||
|
|
||||||
TimestampMonitorValue getRecentDelayEntry();
|
long calculateMinDelay(long timeWindowNs);
|
||||||
|
|
||||||
|
long calculateMinDelay(Long128 currentTime, long timeWindowNs);
|
||||||
|
|
||||||
|
TimestampMonitorValue getRecentDelayEntry();
|
||||||
|
|
||||||
|
|
||||||
// ==================== 全局统计方法 ====================
|
// ==================== 全局统计方法 ====================
|
||||||
|
|||||||
@@ -8,22 +8,26 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
private final int length;
|
private final int length;
|
||||||
private final TimestampMonitorKey<?> key;
|
private final TimestampMonitorKey<?> key;
|
||||||
private long delay;
|
private long delay;
|
||||||
|
private long delayMin;
|
||||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length) {
|
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length) {
|
||||||
this(key,timestamp,count,length,Long.MAX_VALUE/1024);
|
this(key,timestamp,count,length,Long.MAX_VALUE/1024,Long.MAX_VALUE/1024);
|
||||||
}
|
}
|
||||||
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length,long delay) {
|
public TimestampMonitorValue(TimestampMonitorKey<?> key, Long128 timestamp,int count, int length,long delay,long delayMin) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.count=count;
|
this.count=count;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
this.delay=delay;
|
this.delay=delay;
|
||||||
|
this.delayMin=delayMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
result = prime * result + count;
|
||||||
result = prime * result + (int) (delay ^ (delay >>> 32));
|
result = prime * result + (int) (delay ^ (delay >>> 32));
|
||||||
|
result = prime * result + (int) (delayMin ^ (delayMin >>> 32));
|
||||||
result = prime * result + length;
|
result = prime * result + length;
|
||||||
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
||||||
return result;
|
return result;
|
||||||
@@ -38,8 +42,12 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
TimestampMonitorValue other = (TimestampMonitorValue) obj;
|
||||||
|
if (count != other.count)
|
||||||
|
return false;
|
||||||
if (delay != other.delay)
|
if (delay != other.delay)
|
||||||
return false;
|
return false;
|
||||||
|
if (delayMin != other.delayMin)
|
||||||
|
return false;
|
||||||
if (length != other.length)
|
if (length != other.length)
|
||||||
return false;
|
return false;
|
||||||
if (timestamp == null) {
|
if (timestamp == null) {
|
||||||
@@ -52,8 +60,8 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TimestampMonitorValue [timestamp=" + timestamp + ", length=" + length + ", key=" + key + ", delay="
|
return "TimestampMonitorValue [timestamp=" + timestamp + ", count=" + count + ", length=" + length
|
||||||
+ delay + "]";
|
+ ", delay=" + delay + ", delayMin=" + delayMin + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long128 getTimestamp() { return timestamp; }
|
public Long128 getTimestamp() { return timestamp; }
|
||||||
@@ -73,6 +81,12 @@ public class TimestampMonitorValue implements Comparable<TimestampMonitorValue>
|
|||||||
this.delay = delay;
|
this.delay = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getDelayMin() {
|
||||||
|
return delayMin;
|
||||||
|
}
|
||||||
|
public void setDelayMin(long delayMin) {
|
||||||
|
this.delayMin = delayMin;
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(TimestampMonitorValue other) {
|
public int compareTo(TimestampMonitorValue other) {
|
||||||
return this.timestamp.compareTo(other.timestamp);
|
return this.timestamp.compareTo(other.timestamp);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class NTPContext implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void putPacket(NTPv4Packet nv4, MultiProtocolSocketAddress inetSocketAddress) {
|
protected void putPacket(NTPv4Packet nv4, MultiProtocolSocketAddress inetSocketAddress) {
|
||||||
checkIP();
|
//checkIP();
|
||||||
List<NTPv4Packet> newv = new Vector<NTPv4Packet>();
|
List<NTPv4Packet> newv = new Vector<NTPv4Packet>();
|
||||||
List<NTPv4Packet> oldv = recvmap.putIfAbsent(inetSocketAddress, newv);
|
List<NTPv4Packet> oldv = recvmap.putIfAbsent(inetSocketAddress, newv);
|
||||||
if (oldv == null) {
|
if (oldv == null) {
|
||||||
@@ -132,25 +132,6 @@ public class NTPContext implements Closeable, AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkIP() {
|
|
||||||
Set<Entry<MultiProtocolSocketAddress, List<NTPv4Packet>>> ens = recvmap.entrySet();
|
|
||||||
for (Iterator<Entry<MultiProtocolSocketAddress, List<NTPv4Packet>>> iterator = ens.iterator(); iterator
|
|
||||||
.hasNext();) {
|
|
||||||
Entry<MultiProtocolSocketAddress, List<NTPv4Packet>> entry = (Entry<MultiProtocolSocketAddress, List<NTPv4Packet>>) iterator
|
|
||||||
.next();
|
|
||||||
AtomicBoolean ab = new AtomicBoolean(false);
|
|
||||||
ios.forEach((x) -> {
|
|
||||||
if (!ab.get())
|
|
||||||
if (x.findPeer(entry.getKey()) != null) {
|
|
||||||
ab.set(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!ab.get()) {
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PeerInfo implements Comparable<PeerInfo> {
|
private class PeerInfo implements Comparable<PeerInfo> {
|
||||||
private MultiProtocolSocketAddress address;
|
private MultiProtocolSocketAddress address;
|
||||||
@@ -225,14 +206,12 @@ public class NTPContext implements Closeable, AutoCloseable {
|
|||||||
PeerInfo pix = peerInfo.get(0);
|
PeerInfo pix = peerInfo.get(0);
|
||||||
currentClock = pix;
|
currentClock = pix;
|
||||||
int i;
|
int i;
|
||||||
int m = Math.min(peerInfo.size(), 3);
|
List<Long128> adjts = new ArrayList<>();
|
||||||
Long128 bi = Long128.ZERO;
|
for (i = 0; i < peerInfo.size(); i++) {
|
||||||
for (i = 0; i < m; i++) {
|
adjts.add(peerInfo.get(i).getAdj());
|
||||||
PeerInfo pi = peerInfo.get(i);
|
|
||||||
Long128 adjt = pi.getAdj();
|
|
||||||
bi = bi.add(adjt);
|
|
||||||
}
|
}
|
||||||
Long128 delta = bi.divide(Long128.valueOf(i));
|
Long128 delta = NTPTimestamps. median(adjts);
|
||||||
|
//System.out.println(adjts+":"+delta);
|
||||||
avgAdj=(avgAdj*7+delta.abs().longValue())/8;
|
avgAdj=(avgAdj*7+delta.abs().longValue())/8;
|
||||||
Long128 deltaabs=delta.abs();
|
Long128 deltaabs=delta.abs();
|
||||||
if (deltaabs.compareTo(adjustThreshold0) > 0&&firstSync.compareAndSet(true, false)) {
|
if (deltaabs.compareTo(adjustThreshold0) > 0&&firstSync.compareAndSet(true, false)) {
|
||||||
|
|||||||
@@ -252,14 +252,23 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
|||||||
checkLock.unlock();
|
checkLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 在类成员变量中定义 ThreadLocal 发送缓冲区
|
||||||
|
private static final ThreadLocal<ByteBuffer> NTP_TX_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(9000));
|
||||||
|
|
||||||
private void sendNTPPacket(NTPv4Packet nv4, SocketAddress target) throws IOException {
|
private void sendNTPPacket(NTPv4Packet nv4, SocketAddress target) throws IOException {
|
||||||
ByteBuffer bbf = ByteBuffer.allocate(65535);
|
// 1. 获取并重置缓冲区
|
||||||
|
ByteBuffer bbf = NTP_TX_BUFFER.get();
|
||||||
|
bbf.clear(); // 重置 position=0, limit=9000
|
||||||
|
|
||||||
|
// 2. 写入数据
|
||||||
nv4.writeToChannel(KNEChannels.newWritableChannel(bbf));
|
nv4.writeToChannel(KNEChannels.newWritableChannel(bbf));
|
||||||
bbf.flip();
|
bbf.flip(); // 切换为读模式,limit 会变成实际写入的长度
|
||||||
|
|
||||||
|
// 3. 发送
|
||||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||||
dp.setSocketAddress(target);
|
dp.setSocketAddress(target);
|
||||||
dgs.send(dp);
|
dgs.send(dp);
|
||||||
|
|
||||||
if (showPacket)
|
if (showPacket)
|
||||||
System.out.println("NTPv4 TX:" + target + " " + nv4);
|
System.out.println("NTPv4 TX:" + target + " " + nv4);
|
||||||
}
|
}
|
||||||
@@ -379,15 +388,30 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
|||||||
return sends;
|
return sends;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. 在类成员变量中定义 ThreadLocal 缓冲区
|
||||||
|
private static final ThreadLocal<ByteBuffer> NTP_BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(9000));
|
||||||
|
|
||||||
private NTPv4Packet receiveNTPPacket(AtomicReference<InetSocketAddress> isa) throws IOException {
|
private NTPv4Packet receiveNTPPacket(AtomicReference<InetSocketAddress> isa) throws IOException {
|
||||||
ByteBuffer bbf = ByteBuffer.allocate(65535);
|
// 2. 从 ThreadLocal 获取,并重置状态 (position=0, limit=9000)
|
||||||
|
ByteBuffer bbf = NTP_BUFFER.get();
|
||||||
|
bbf.clear();
|
||||||
|
|
||||||
|
// 3. 构造 DatagramPacket
|
||||||
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
DatagramPacket dp = new DatagramPacket(bbf.array(), bbf.limit());
|
||||||
dgs.receive(dp);
|
dgs.receive(dp);
|
||||||
|
|
||||||
isa.set((InetSocketAddress) dp.getSocketAddress());
|
isa.set((InetSocketAddress) dp.getSocketAddress());
|
||||||
|
|
||||||
|
// 4. 关键:限制 ByteBuffer 的读取范围,防止越界读取历史脏数据
|
||||||
|
bbf.limit(dp.getLength());
|
||||||
|
|
||||||
NTPv4Packet nv4 = new NTPv4Packet(context.getClock());
|
NTPv4Packet nv4 = new NTPv4Packet(context.getClock());
|
||||||
|
// 5. 将 Channel 的读取操作限制在 dp.getLength() 长度内
|
||||||
nv4.readFromChannel(KNEChannels.newReadableChannel(bbf), dp.getLength());
|
nv4.readFromChannel(KNEChannels.newReadableChannel(bbf), dp.getLength());
|
||||||
|
|
||||||
if (showPacket)
|
if (showPacket)
|
||||||
System.out.println("NTPv4 RX:" + isa.get() + " " + nv4);
|
System.out.println("NTPv4 RX:" + isa.get() + " " + nv4);
|
||||||
|
|
||||||
return nv4;
|
return nv4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,18 +429,5 @@ public class NTPv4Protocol implements Closeable, AutoCloseable {
|
|||||||
return dgs.isClosed();
|
return dgs.isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
|
||||||
HighAccuracyClock hac = new HighAccuracyClock();
|
|
||||||
NTPContext context = new NTPContext(hac);
|
|
||||||
System.out.println(context);
|
|
||||||
NTPv4Protocol nvc = new NTPv4Protocol(context, new MultiProtocolSocketAddress("{UDP}0.0.0.0:123"));// 106.55.184.199
|
|
||||||
nvc.getPeers().add(new NTPPeer("{UDP}106.55.184.199:123", NTPv4Packet.NTP_CLIENT));
|
|
||||||
nvc.getPeers().add(new NTPPeer("{UDP}time.windows.com:123", NTPv4Packet.NTP_CLIENT));
|
|
||||||
nvc.getPeers().add(new NTPPeer("{UDP}127.0.0.1:123", NTPv4Packet.NTP_SYMMETRIC_ACTIVE));
|
|
||||||
/*
|
|
||||||
* for (int i = 0; i < 10000; i++) { Thread.sleep(1000);
|
|
||||||
* System.out.println(context.getCurrentSelfDispersion128());
|
|
||||||
* System.out.println(context); }
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ import java.io.IOException;
|
|||||||
import java.nio.channels.UnresolvedAddressException;
|
import java.nio.channels.UnresolvedAddressException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.kne.cloud.clock.AdjustedNanoClock;
|
import org.kne.cloud.clock.AdjustedNanoClock;
|
||||||
import org.kne.cloud.clock.HighAccuracyClock;
|
import org.kne.cloud.clock.HighAccuracyClock;
|
||||||
|
import org.kne.cloud.clock.NTPTimestamps;
|
||||||
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
||||||
import org.kne.cloud.network.SpeedLimiter;
|
import org.kne.cloud.network.SpeedLimiter;
|
||||||
import org.kne.cloud.network.ThreadTool;
|
import org.kne.cloud.network.ThreadTool;
|
||||||
import org.kne.cloud.network.klalb.KLALBPacket;
|
import org.kne.cloud.network.klalb.*;
|
||||||
import org.kne.cloud.network.klalb.KLALBPacketLink;
|
|
||||||
import org.kne.cloud.network.klalb.KLALBUtils;
|
|
||||||
import org.kne.cloud.network.klalb.PINGPacket;
|
|
||||||
import org.kne.cloud.network.klalb.PONGPacket;
|
|
||||||
import org.kne.cloud.network.monitor.LinkStatus;
|
import org.kne.cloud.network.monitor.LinkStatus;
|
||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
import org.kne.concurrent.ThreadParker;
|
import org.kne.concurrent.ThreadParker;
|
||||||
|
import org.kne.math.Long128;
|
||||||
|
|
||||||
public class Kperf implements Runnable{
|
public class Kperf implements Runnable{
|
||||||
|
|
||||||
@@ -38,8 +38,8 @@ public class Kperf implements Runnable{
|
|||||||
private volatile KLALBPacketLink link;
|
private volatile KLALBPacketLink link;
|
||||||
|
|
||||||
private LinkStatus status=new LinkStatus();
|
private LinkStatus status=new LinkStatus();
|
||||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(HighAccuracyClock.SYSTEM_CLOCK);
|
private HighAccuracyClock sysclk =HighAccuracyClock.SYSTEM_CLOCK;
|
||||||
|
private SpeedAndTrafficAndDelayMonitorDataImpl monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||||
private volatile boolean closed = false;
|
private volatile boolean closed = false;
|
||||||
|
|
||||||
private volatile ThreadParker tlock=new ThreadParker();
|
private volatile ThreadParker tlock=new ThreadParker();
|
||||||
@@ -79,25 +79,20 @@ public class Kperf implements Runnable{
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
KLALBPacket testPacket=null;
|
private KLALBPacket testPacket=null;
|
||||||
|
|
||||||
private long starttime=System.nanoTime();
|
private long starttime=System.nanoTime();
|
||||||
long totaltime=1000;
|
|
||||||
long usedtime=0;
|
|
||||||
|
|
||||||
|
|
||||||
private MonitorUpdater monitorUpdater;
|
private ScheduledFuture<?> monitorUpdater;
|
||||||
private class MonitorUpdater implements Runnable{
|
private class MonitorUpdater implements Runnable{
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!closed) {
|
if (closed) {
|
||||||
|
monitorUpdater.cancel(false);
|
||||||
|
}else{
|
||||||
status.updateReliability();
|
status.updateReliability();
|
||||||
monitor.update();
|
monitor.update();
|
||||||
try {
|
|
||||||
Thread.sleep(1);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,9 +121,9 @@ public class Kperf implements Runnable{
|
|||||||
});
|
});
|
||||||
Thread tc = ThreadTool.makeVDaemonThreadIfSupport("测速控制线程", () -> {
|
Thread tc = ThreadTool.makeVDaemonThreadIfSupport("测速控制线程", () -> {
|
||||||
final int wtimes=5;
|
final int wtimes=5;
|
||||||
totaltime=(20*1000*1+20*1000*4+wtimes*1000*5)*1000000L;
|
|
||||||
starttime=System.nanoTime();
|
|
||||||
System.out.println("测速开始!");
|
System.out.println("测速开始!");
|
||||||
|
if(reports!=null)
|
||||||
|
reports.updateDial(monitor);
|
||||||
try {
|
try {
|
||||||
long startTime;
|
long startTime;
|
||||||
|
|
||||||
@@ -137,7 +132,6 @@ public class Kperf implements Runnable{
|
|||||||
startTime=System.nanoTime();
|
startTime=System.nanoTime();
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
updateUsedTime();
|
|
||||||
}
|
}
|
||||||
System.out.printf("上传延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getOutDelay()/1000000.0,monitor.getOutDelay()/1000000.0,monitor.getOutJitter()/1000000.0);
|
System.out.printf("上传延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getOutDelay()/1000000.0,monitor.getOutDelay()/1000000.0,monitor.getOutJitter()/1000000.0);
|
||||||
System.out.printf("下载延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getInDelay()/1000000.0,monitor.getInDelay()/1000000.0,monitor.getInJitter()/1000000.0);
|
System.out.printf("下载延迟 最小:%.3fms 平均:%.3fms 抖动:%.3fms\n",monitor.getInDelay()/1000000.0,monitor.getInDelay()/1000000.0,monitor.getInJitter()/1000000.0);
|
||||||
@@ -153,7 +147,7 @@ public class Kperf implements Runnable{
|
|||||||
|
|
||||||
System.out.println("测试2/3:带宽测试");
|
System.out.println("测试2/3:带宽测试");
|
||||||
test.setLimitspeed(1000L*1024L*1024L*1024L);
|
test.setLimitspeed(1000L*1024L*1024L*1024L);
|
||||||
testPacket=new TESTNPacket(65535);
|
testPacket=new TESTNPacket(9000);
|
||||||
for (int i = 0; i < 60; i++) {
|
for (int i = 0; i < 60; i++) {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
@@ -208,7 +202,9 @@ public class Kperf implements Runnable{
|
|||||||
|
|
||||||
while ((!link.isClosed()) && (!closed)) {
|
while ((!link.isClosed()) && (!closed)) {
|
||||||
if (checkPingTimeSleep()) {
|
if (checkPingTimeSleep()) {
|
||||||
writePacketToKPL(new PINGPacket(System.nanoTime(),0, 0));
|
PINGPacket ping = new PINGPacket(sysclk.getCurrentTimeNTP64().longValue(), monitor.getOutSpeed(),
|
||||||
|
monitor.getInSpeed());
|
||||||
|
writePacketToKPL(ping);
|
||||||
|
|
||||||
}else {
|
}else {
|
||||||
KLALBPacket kpip = IsendDequeList.poll();
|
KLALBPacket kpip = IsendDequeList.poll();
|
||||||
@@ -251,7 +247,17 @@ public class Kperf implements Runnable{
|
|||||||
}
|
}
|
||||||
switch (kpp.getType()) {
|
switch (kpp.getType()) {
|
||||||
case KLALBPacket.PING:
|
case KLALBPacket.PING:
|
||||||
sendIPacket(new PONGPacket(((PINGPacket) kpp).getTime() ,kpp.getRcvtime(), System.nanoTime(),0, 0));
|
long pct = System.nanoTime() - kpp.getRcvtime();
|
||||||
|
Long128 curr = sysclk.getCurrentTimeNanos();
|
||||||
|
Long128 rcv = curr.subtract(pct);
|
||||||
|
|
||||||
|
Long128 local1281 = NTPTimestamps.nanosToNtp128BitTimestamp(curr);
|
||||||
|
PONGPacket pong = new PONGPacket(((PINGPacket) kpp).getTime(),
|
||||||
|
NTPTimestamps.ntp128To64(NTPTimestamps.nanosToNtp128BitTimestamp(rcv)).longValue(),
|
||||||
|
NTPTimestamps.ntp128To64(NTPTimestamps.nanosToNtp128BitTimestamp(curr)).longValue(),
|
||||||
|
monitor.getUploadBandwidth().calculateBandwidth(500000000L),
|
||||||
|
monitor.getDownloadBandwidth().calculateBandwidth(500000000L));
|
||||||
|
sendIPacket(pong);
|
||||||
break;
|
break;
|
||||||
case KLALBPacket.PONG:
|
case KLALBPacket.PONG:
|
||||||
if (fst) {
|
if (fst) {
|
||||||
@@ -270,42 +276,45 @@ public class Kperf implements Runnable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
PONGPacket png = (PONGPacket) kpp;
|
PONGPacket png = (PONGPacket) kpp;
|
||||||
long ul = png.getRcvtime() - png.getTimepingsnd()-(png.getTimepongsnd()-png.getTimepingrcv());
|
Long128 local = sysclk.getCurrentTimeNanos();
|
||||||
|
Long128 local128 = NTPTimestamps.nanosToNtp128BitTimestamp(local);
|
||||||
|
|
||||||
long DsndDelayFactor0 = png.getTimepingrcv() - png.getTimepingsnd();
|
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||||
long DrcvDelayFactor0 = png.getRcvtime() - png.getTimepongsnd();
|
NTPTimestamps.inferNtp64To128(png.getTimepingsnd(), local128));
|
||||||
long DsndDelayFactor;
|
// System.out.println("psnd"+NTPTimestamps.nanosSince1970ToString(
|
||||||
long DrcvDelayFactor;
|
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||||
|
// psnd,local128))));
|
||||||
|
Long128 prcv = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||||
|
NTPTimestamps.inferNtp64To128(png.getTimepingrcv(), local128));
|
||||||
|
// System.out.println("prcv"+NTPTimestamps.nanosSince1970ToString(
|
||||||
|
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||||
|
// prcv,local128))));
|
||||||
|
Long128 posnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||||
|
NTPTimestamps.inferNtp64To128(png.getTimepongsnd(), local128));
|
||||||
|
// System.out.println("posnd"+NTPTimestamps.nanosSince1970ToString(
|
||||||
|
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||||
|
// posnd,local128))));
|
||||||
|
|
||||||
adjnc.getLock().lock();
|
long DsndDelay = prcv.subtract(psnd).longValue();
|
||||||
try {
|
long DrcvDelay = local.subtract(posnd).longValue();
|
||||||
adjnc.calibrate(png.getTimepongsnd() + ul / 2 - png.getRcvtime(), ul / 2);
|
// System.out.println(DsndDelay+" "+DrcvDelay);
|
||||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
|
||||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
|
||||||
if (DsndDelayFactor < 0) {
|
|
||||||
if (DrcvDelayFactor < 0) {
|
|
||||||
|
|
||||||
} else {
|
long rtt = DsndDelay + DrcvDelay;
|
||||||
adjnc.setDelta(adjnc.getDelta() + DsndDelayFactor);
|
if (DsndDelay >= 0 && DrcvDelay >= 0) {
|
||||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
monitor.recordUploadDelay(DsndDelay);
|
||||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
monitor.recordDownloadDelay(DrcvDelay);
|
||||||
}
|
//sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.001);
|
||||||
} else {
|
} else {
|
||||||
if (DrcvDelayFactor < 0) {
|
long Dfallback = rtt / 2;
|
||||||
adjnc.setDelta(adjnc.getDelta() - DrcvDelayFactor);
|
if (Dfallback >= 0) {
|
||||||
DsndDelayFactor = DsndDelayFactor0 - adjnc.getDelta();
|
monitor.recordUploadDelay(Dfallback);
|
||||||
DrcvDelayFactor = DrcvDelayFactor0 + adjnc.getDelta();
|
monitor.recordDownloadDelay(Dfallback);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
// sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.1);
|
||||||
adjnc.getLock().unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tlock.unpark();
|
tlock.unpark();
|
||||||
updateUsedTime() ;
|
|
||||||
if(reports!=null)
|
|
||||||
reports.updateDial(monitor);
|
|
||||||
break;
|
break;
|
||||||
case KLALBPacket.TESTN:
|
case KLALBPacket.TESTN:
|
||||||
break;
|
break;
|
||||||
@@ -330,12 +339,7 @@ public class Kperf implements Runnable{
|
|||||||
tcc.interrupt();
|
tcc.interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void updateUsedTime() {
|
|
||||||
usedtime=System.nanoTime()-starttime;
|
|
||||||
//System.out.println(usedtime+" "+totaltime);
|
|
||||||
if(reports!=null)
|
|
||||||
reports.testProcess(usedtime/(double)totaltime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -436,8 +440,7 @@ public class Kperf implements Runnable{
|
|||||||
|
|
||||||
|
|
||||||
public void startPerfing() {
|
public void startPerfing() {
|
||||||
monitorUpdater=new MonitorUpdater();
|
monitorUpdater= KLALBScheduler.getScheduler().scheduleWithFixedDelay(new MonitorUpdater(),1,1, TimeUnit.MILLISECONDS);
|
||||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
|
||||||
ThreadTool.makeVDaemonThreadIfSupport("测速接收线程" ,this).start();
|
ThreadTool.makeVDaemonThreadIfSupport("测速接收线程" ,this).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.kne.cloud.network.perf;
|
|||||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||||
|
|
||||||
public interface KperfReports {
|
public interface KperfReports {
|
||||||
public void testProcess(double d);
|
|
||||||
public void testFinish();
|
public void testFinish();
|
||||||
public void updateDial(SpeedAndTrafficAndDelayMonitorDataImpl mdt);
|
public void updateDial(SpeedAndTrafficAndDelayMonitorDataImpl mdt);
|
||||||
public void uploadSpeedFinish(long uploadSpeed);
|
public void uploadSpeedFinish(long uploadSpeed);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user