From 455139dfe918639d4a54f0275c717863a3acab3f Mon Sep 17 00:00:00 2001 From: SerinaNya <34389622+SerinaNya@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:34:41 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=96=B0=E5=A2=9E=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E4=BF=A1=E6=81=AF=E4=B8=8E=E9=A2=9D=E5=A4=96=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E8=AE=BE=E7=BD=AE=EF=BC=8C=E6=94=AF=E6=8C=81=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=90=8D=E5=B9=BF=E6=92=AD=E5=8F=8ATUN=E6=98=BE?= =?UTF-8?q?=E5=BC=8F=E7=A6=81=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 设置页新增设备名称(单行)、设备描述(多行)、额外路由(CIDR列表)设置项 - RouterInfo 广播携带 deviceName,并在拓扑图节点与节点概览中展示;deviceDescription 保持本地概览显示 - 拓扑图节点标签支持多行文本绘制 - 节点概览面板新增 IP 地址及设备详情展示 - 支持将 TUNName 设为 null/"null"/空字符串时完全跳过 Wintun 虚拟网卡创建 - .classpath 容器改为标准 JavaSE-25 执行环境以同时兼容 JDK 25 与 26 - 新增 AGENTS.md 与 VS Code 调试及运行配置 BREAKING CHANGE: RouterInfo 在序列化末尾追加了 deviceName 字段(writeUTF),新旧版本节点混连时路由协议解析异常,需同步升级 --- .classpath | 2 +- .project | 11 +++ .vscode/launch.json | 27 +++++++ .vscode/settings.json | 9 +++ AGENTS.md | 55 +++++++++++++ klalb-config.json | 5 +- src/klalb_en_US.properties | 4 + src/klalb_zh_CN.properties | 4 + .../cloud/network/klalb/KLALBController.java | 8 +- .../klalb/KLALBControllerConfigItem.java | 34 +++++++- .../kne/cloud/network/klalb/KLALBUtils.java | 21 +++++ .../cloud/network/klalb/ui/GraphPanel.java | 11 ++- .../network/klalb/ui/KLALBStateGUI3.java | 77 ++++++++++++++++++- .../network/klalb/ui/NetworkGraphPanel.java | 22 +++++- .../klalb/ui/NodeInformationPanel.java | 23 ++++++ .../network/srv6/KLALBRoutingProtocol.java | 14 ++++ .../kne/cloud/network/srv6/RouterInfo.java | 11 +++ .../kne/cloud/network/srv6/SRv6Router.java | 9 +++ 18 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 AGENTS.md diff --git a/.classpath b/.classpath index 60354f2..7200fd3 100644 --- a/.classpath +++ b/.classpath @@ -24,7 +24,7 @@ - + diff --git a/.project b/.project index b5f524a..0359fa5 100644 --- a/.project +++ b/.project @@ -14,4 +14,15 @@ org.eclipse.jdt.core.javanature + + + 1787317094049 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..75587bd --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,27 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "KLALBMain (VS Code 自动构建)", + "request": "launch", + "mainClass": "org.kne.cloud.network.klalb.KLALBMain", + "projectName": "KLALB", + "cwd": "${workspaceFolder}", + "vmArgs": "--enable-native-access=ALL-UNNAMED --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED" + }, + { + "type": "java", + "name": "KLALBMain (直接用 bin 目录)", + "request": "launch", + "mainClass": "org.kne.cloud.network.klalb.KLALBMain", + "cwd": "${workspaceFolder}", + "classPaths": [ + "${workspaceFolder}/bin", + "${workspaceFolder}/src", + "${workspaceFolder}/lib/*" + ], + "vmArgs": "--enable-native-access=ALL-UNNAMED --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..907ed05 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "java.configuration.runtimes": [ + { + "name": "JavaSE-25", + "path": "C:\\Program Files\\Eclipse Adoptium\\jdk-25.0.4.7-hotspot", + "default": true + } + ] +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..62671b6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,55 @@ +# AGENTS.md + +KLALB ("KLALB Decentralized SRv6 Network") — Java load-balancing/tunnel system that merges multiple WAN links into one virtual IPv6/SRv6 network. Version constant lives in `src/org/kne/cloud/network/klalb/CONST.java`. Protocol specs and manuals are the Chinese `.docx` files in the repo root. + +## Build & run + +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): + +```powershell +& javac -encoding UTF-8 -cp "lib/*" -d bin (Get-ChildItem -Recurse src -Filter *.java | ForEach-Object FullName) +``` + +Run from the repo root — CWD matters: +- reads `klalb-config.json` from CWD +- loads native libs from CWD: `tuntap4j.dll/.so/.dylib`, `wintun.dll`, `fastcopy.dll` (TUN device support) +- classpath must include `src` as well as `bin`: i18n bundles (`/klalb_*.properties`) and images (`/assets/*`) are classpath resources that Eclipse copies to `bin` but manual `javac` does not + +```powershell +java --enable-native-access=ALL-UNNAMED "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED" -cp "bin;src;lib/*" org.kne.cloud.network.klalb.KLALBMain +``` + +IDE metadata targets JDK 26 (`jdk-26.0.1`); the tree also compiles cleanly on JDK 25. `.classpath` now references the standard container `JavaSE-25` — an execution-environment spec that any JDK ≥25 satisfies, so it works unchanged on JDK 26 machines too (the original named `jdk-26.0.1` VM broke VS Code import on machines without it). `.vscode/settings.json` maps `JavaSE-25` to the locally installed Adoptium JDK; register every installed JDK there when adding another one. Keep compiler compliance ≤25 (`.settings` pins 19) so both JDKs stay usable. + +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). +- 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"`. +- Routing broadcast (`RouterInfo`) transmits `deviceName` across the network, which topology and node overview panels display. `deviceDescription` and `ExtraRoutes` remain local controller configs. + +## Verification + +No test suite, no CI. Classes named `*Test*` (`nathole/`, `ntp/`) are manual `main()` harnesses requiring real network peers. Practical check = compile succeeds + app launches. + +## 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`, ...). +- `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.congestion` — pluggable congestion control (BBR, Vegas2, DCTCP...), chosen via `"congestionAlgorithm"` in config. +- `...network.kltp` — custom reliable transport protocol (packets/streams). +- `...network.ipv6`, `...network.srv6` — packet codecs, route table, Dijkstra path computation. +- `...network.frpc` — frp client integration. +- `...klalb.ui` — all Swing UI code. + +## 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`). + +## Conventions + +- Sources are UTF-8; comments, log/UI strings, and commit messages are largely Chinese. +- UI strings go through `UIEnv.getRsb().getString(...)`; add keys to **both** `src/klalb_zh_CN.properties` and `src/klalb_en_US.properties`. +- `client.cfg`, `server.cfg`, `linetable.txt` at the root are example line-table/port-rule files loaded via the GUI file picker — not hardwired paths. diff --git a/klalb-config.json b/klalb-config.json index 2d06737..9be7de6 100644 --- a/klalb-config.json +++ b/klalb-config.json @@ -37,6 +37,7 @@ "ntp://ntp.ntsc.ac.cn", "ntp://us.ntp.org.cn" ], + "ExtraRoutes": [], "denyLineTableQuery": false, "denyLineTableBroadcast": false, "congestionAlgorithm": "BBR", @@ -46,8 +47,10 @@ "nagleDelayTime": 1000000, "linkNagleDelayTime": 0, "linkConnectionsCount": 1, - "TUNName": "KLALB_SRv6", + "TUNName": null, "performanceStrategy": "multiscatter", + "DeviceName": "SerinaNya PC", + "DeviceDescription": "desc", "NetworkInterfaceExcepts": [], "Type": "KLALBController" }, diff --git a/src/klalb_en_US.properties b/src/klalb_en_US.properties index a4a76cd..97ed089 100644 --- a/src/klalb_en_US.properties +++ b/src/klalb_en_US.properties @@ -3,7 +3,10 @@ networkgraph=Network graph language=Language basicsettings=Basic settings ipv6addr=IPv6 address +devicename=Device name +devicedescription=Device description dnsserver=DNS server +extraroutes=Extra routes asnumber=AS number tcplistening=TCP listening udplistening=UDP listening @@ -34,6 +37,7 @@ saveconfigsuccess=Save config success warning=Warning invaildipv6addr=IPv6 address:Invaild Input invailddnsserver=DNS server:Invaild Input +invaildextraroutes=Extra routes:Invaild Input invaildasnumber=AS number:Invaild Input invaildtcplisten=TCP listen:Invaild Input invaildudplisten=UDP listen:Invaild Input diff --git a/src/klalb_zh_CN.properties b/src/klalb_zh_CN.properties index dc97fe8..c1257cd 100644 --- a/src/klalb_zh_CN.properties +++ b/src/klalb_zh_CN.properties @@ -3,7 +3,10 @@ networkgraph=网络拓扑图 language=语言 basicsettings=基本设置 ipv6addr=IPv6地址 +devicename=设备名称 +devicedescription=设备描述 dnsserver=DNS服务器 +extraroutes=额外路由 asnumber=AS号码 tcplistening=TCP监听端口 udplistening=UDP监听端口 @@ -34,6 +37,7 @@ saveconfigsuccess=保存配置成功 warning=警告 invaildipv6addr=IPv6地址:非法输入 invailddnsserver=DNS服务器:非法输入 +invaildextraroutes=额外路由:非法输入 invaildasnumber=AS号码:非法输入 invaildtcplisten=TCP监听端口:非法输入 invaildudplisten=UDP监听端口:非法输入 diff --git a/src/org/kne/cloud/network/klalb/KLALBController.java b/src/org/kne/cloud/network/klalb/KLALBController.java index dd6a8e1..3eb1857 100644 --- a/src/org/kne/cloud/network/klalb/KLALBController.java +++ b/src/org/kne/cloud/network/klalb/KLALBController.java @@ -637,6 +637,7 @@ public class KLALBController { srv6Router = new SRv6Router(selfx, clock); if(configItem!=null) { srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy())); + srv6Router.setDeviceName(configItem.getDeviceName()); } srv6Router.runKLALBRouteProtocol(); routingProtocol = srv6Router.getKlalbRouteProtol(); @@ -647,10 +648,11 @@ public class KLALBController { System.out.println(" Loaded: SRv6 Stack"); String name=(configItem!=null)?configItem.getTUNName():CONST.KLALB_S_RV6; - if (enableVirtualAdapter&&(name!=null)) { + boolean enableTUN = enableVirtualAdapter && (name != null) && !name.trim().isEmpty() && !name.trim().equalsIgnoreCase("null"); + if (enableTUN) { Thread t=new Thread(()->{ try { - IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name, + IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(), new IPv6AddressGroup(srv6Router.getLocator().getAddress(), 32), SRv6Router.MTU, dnsAddresses); tunlink.setMonitor(datatMonitor); // srv6Router.getLinkTabel().add(tunlink); @@ -664,7 +666,7 @@ public class KLALBController { }); t.start(); }else { - System.out.println(" Tun Adapter Disbaled"); + System.out.println(" Tun Adapter Disabled"); } udpr=new UDPProtocolRegister(this); diff --git a/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java b/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java index 9b7966a..76d6bfa 100644 --- a/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java +++ b/src/org/kne/cloud/network/klalb/KLALBControllerConfigItem.java @@ -19,6 +19,7 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { private ListLineTable=new ArrayList<>(); private ListConnectLineTable=new ArrayList<>(); private ListntpServerTable=new ArrayList<>(); + private ListExtraRoutes=new ArrayList<>(); private boolean denyLineTableQuery=false; private boolean denyLineTableBroadcast=false; private String congestionAlgorithm="BBR"; @@ -30,6 +31,8 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { private int linkConnectionsCount=1; private String TUNName=CONST.KLALB_S_RV6; private String performanceStrategy="multifill"; + private String DeviceName; + private String DeviceDescription; public String getPerformanceStrategy() { return performanceStrategy; @@ -39,6 +42,22 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { this.performanceStrategy = performanceStrategy; } + public String getDeviceName() { + return DeviceName; + } + + public void setDeviceName(String deviceName) { + DeviceName = deviceName; + } + + public String getDeviceDescription() { + return DeviceDescription; + } + + public void setDeviceDescription(String deviceDescription) { + DeviceDescription = deviceDescription; + } + public void setNetworkInterfaceExcepts(List networkInterfaceExcepts) { NetworkInterfaceExcepts = networkInterfaceExcepts; } @@ -193,6 +212,14 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { this.ntpServerTable = ntpServerTable; } + public List getExtraRoutes() { + return ExtraRoutes; + } + + public void setExtraRoutes(List extraRoutes) { + ExtraRoutes = extraRoutes; + } + @@ -328,6 +355,7 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { ", LineTable=" + LineTable + ", ConnectLineTable=" + ConnectLineTable + ", ntpServerTable=" + ntpServerTable + + ", ExtraRoutes=" + ExtraRoutes + ", denyLineTableQuery=" + denyLineTableQuery + ", denyLineTableBroadcast=" + denyLineTableBroadcast + ", congestionAlgorithm='" + congestionAlgorithm + '\'' + @@ -339,6 +367,8 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { ", linkConnectionsCount=" + linkConnectionsCount + ", TUNName='" + TUNName + '\'' + ", performanceStrategy='" + performanceStrategy + '\'' + + ", DeviceName='" + DeviceName + '\'' + + ", DeviceDescription='" + DeviceDescription + '\'' + ", NetworkInterfaceExcepts=" + NetworkInterfaceExcepts + '}'; } @@ -348,11 +378,11 @@ public class KLALBControllerConfigItem extends KLALBConfigItem { if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; 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(congestionAlgorithm, that.congestionAlgorithm) && Objects.equals(TUNName, that.TUNName) && Objects.equals(performanceStrategy, that.performanceStrategy) && Objects.equals(NetworkInterfaceExcepts, that.NetworkInterfaceExcepts); + 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); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), language, nogui, VirtualAddress, VirtualASN, DNS, TCPListen, UDPListen, VirtualSocketName, LineTable, ConnectLineTable, ntpServerTable, denyLineTableQuery, denyLineTableBroadcast, congestionAlgorithm, burstLimit, delayUpperBound, delayLowerBound, nagleDelayTime, linkNagleDelayTime, linkConnectionsCount, TUNName, performanceStrategy, NetworkInterfaceExcepts); + 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); } } diff --git a/src/org/kne/cloud/network/klalb/KLALBUtils.java b/src/org/kne/cloud/network/klalb/KLALBUtils.java index 1bedf45..7322633 100644 --- a/src/org/kne/cloud/network/klalb/KLALBUtils.java +++ b/src/org/kne/cloud/network/klalb/KLALBUtils.java @@ -51,6 +51,27 @@ public class KLALBUtils { v[3] = 0x01; return IPv6Address.valueOf(v); } + + public static String parseCidr(String cidr) { + int idx = cidr.indexOf('/'); + if (idx <= 0 || idx == cidr.length() - 1) + throw new IllegalArgumentException("not a cidr: " + cidr); + int prefix; + try { + prefix = Integer.parseInt(cidr.substring(idx + 1)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("bad prefix: " + cidr); + } + try { + InetAddress addr = InetAddress.getByName(cidr.substring(0, idx)); + int max = (addr instanceof Inet6Address) ? 128 : 32; + if (prefix < 0 || prefix > max) + throw new IllegalArgumentException("prefix out of range: " + cidr); + return addr.getHostAddress() + "/" + prefix; + } catch (UnknownHostException e) { + throw new IllegalArgumentException("bad address: " + cidr); + } + } public static void main(String[] args) { System.out.println(uuidToIP(new UUID(-1,-1))); } diff --git a/src/org/kne/cloud/network/klalb/ui/GraphPanel.java b/src/org/kne/cloud/network/klalb/ui/GraphPanel.java index 6a611d5..7da8456 100644 --- a/src/org/kne/cloud/network/klalb/ui/GraphPanel.java +++ b/src/org/kne/cloud/network/klalb/ui/GraphPanel.java @@ -346,7 +346,16 @@ public class GraphPanel extends JPanel { g.setFont(UIEnv.getFont().deriveFont(10.0f)); //g.drawString(text, (int)(x+nodesize/2), (int)(y-nodesize/3)); - g.drawString(text, (int)(x-image.getWidth(null)/2-10), (int)(y+image.getHeight(null)/2+10)); + int imgw=(image!=null)?image.getWidth(null):(int)nodesize; + int imgh=(image!=null)?image.getHeight(null):(int)nodesize; + java.awt.FontMetrics fm=g.getFontMetrics(); + int lineHeight=fm.getHeight()+2; + int textx=(int)(x-imgw/2-10); + int texty=(int)(y+imgh/2+10)+fm.getAscent(); + String[] lines=text.split("\n"); + for (int i = 0; i < lines.length; i++) { + g.drawString(lines[i], textx, texty+i*lineHeight); + } } public Vector2 getPositionVec2() { diff --git a/src/org/kne/cloud/network/klalb/ui/KLALBStateGUI3.java b/src/org/kne/cloud/network/klalb/ui/KLALBStateGUI3.java index 410c8a6..468c927 100644 --- a/src/org/kne/cloud/network/klalb/ui/KLALBStateGUI3.java +++ b/src/org/kne/cloud/network/klalb/ui/KLALBStateGUI3.java @@ -80,6 +80,10 @@ public class KLALBStateGUI3 extends XFrame { private JTextField textFieldLocate; // 定位地址输入框 private JTextField asnField2; // ASN显示框 private JTextArea dnsAreaSet; // DNS服务器设置区域 + private JTextArea extraRoutesSet; // 额外路由设置区域 + private JTextField deviceNameSet; // 设备名称设置框 + private JTextArea deviceDescriptionSet; // 设备描述设置区域 + private KLALBController kcontroller; // 关联的控制器 private JComboBox comboPerformance; // 性能策略选择框 private JComboBox comboCongestion; // 拥塞控制算法选择框 private JTextField tcpListeningSet; // TCP监听设置 @@ -138,6 +142,7 @@ public class KLALBStateGUI3 extends XFrame { * 初始化UI界面 */ private void initUI(KLALBController kc, String title) { + kcontroller = kc; // 设置窗口基本属性 setIconImage(UIEnv.getIcon()); setTitleColor(UIEnv.getDefaultTitleColor()); @@ -785,12 +790,30 @@ public class KLALBStateGUI3 extends XFrame { addressFieldSet = addr6.getTextField(); settings.getView().add(addr6); + // 设备名称设置 + TextSettingItem deviceName = new TextSettingItem(UIEnv.getRsb().getString("devicename"), + CONST.itemwidth, CONST.settingheight); + deviceNameSet = deviceName.getTextField(); + settings.getView().add(deviceName); + + // 设备描述设置 + TextAreaSettingItem deviceDescription = new TextAreaSettingItem(UIEnv.getRsb().getString("devicedescription"), + CONST.itemwidth, CONST.settingheight * 5); + deviceDescriptionSet = deviceDescription.getTextArea(); + settings.getView().add(deviceDescription); + // DNS服务器设置 TextAreaSettingItem dns = new TextAreaSettingItem(UIEnv.getRsb().getString("dnsserver"), CONST.itemwidth, CONST.settingheight * 5); dnsAreaSet = dns.getTextArea(); settings.getView().add(dns); + // 额外路由设置 + TextAreaSettingItem extraRoutes = new TextAreaSettingItem(UIEnv.getRsb().getString("extraroutes"), + CONST.itemwidth, CONST.settingheight * 5); + extraRoutesSet = extraRoutes.getTextArea(); + settings.getView().add(extraRoutes); + // ASN设置 TextSettingItem asn = new TextSettingItem(UIEnv.getRsb().getString("asnumber"), CONST.itemwidth, CONST.settingheight); @@ -1022,6 +1045,26 @@ public class KLALBStateGUI3 extends XFrame { kck.setNogui(nogui.isSelected()); + // 保存设备名称 + String dnametext = deviceNameSet.getText().trim(); + if (dnametext.equals("")) { + kck.setDeviceName(null); + } else { + kck.setDeviceName(dnametext); + } + if (kcontroller != null && kcontroller.getIpv6Router() != null) { + kcontroller.getIpv6Router().setDeviceName(kck.getDeviceName()); + } + + // 保存设备描述 + String ddesctext = deviceDescriptionSet.getText().trim(); + if (ddesctext.equals("")) { + kck.setDeviceDescription(null); + } else { + kck.setDeviceDescription(ddesctext); + } + + // 保存IPv6地址 String ttext = addressFieldSet.getText().trim(); if (ttext.equals("")) { @@ -1058,6 +1101,24 @@ public class KLALBStateGUI3 extends XFrame { } kck.setDNS(iaddr); + // 保存额外路由列表 + String[] spltEr = extraRoutesSet.getText().split("\n"); + List eroutes = new ArrayList<>(); + for (String str : spltEr) { + str = str.trim(); + if (!str.isEmpty()) { + try { + eroutes.add(KLALBUtils.parseCidr(str)); + } catch (RuntimeException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(this, UIEnv.getRsb().getString("invaildextraroutes"), + UIEnv.getRsb().getString("warning"), JOptionPane.WARNING_MESSAGE); + return; + } + } + } + kck.setExtraRoutes(eroutes); + // 保存ASN String asntext = asnFieldSet.getText(); if (asntext.equals("")) { @@ -1073,8 +1134,8 @@ public class KLALBStateGUI3 extends XFrame { } } - String tunNameText=tunDeviceName.getText(); - if(tunNameText.equals("")) { + String tunNameText=tunDeviceName.getText().trim(); + if(tunNameText.equals("") || tunNameText.equalsIgnoreCase("null")) { kck.setTUNName(null); }else { kck.setTUNName(tunNameText); @@ -1453,6 +1514,14 @@ public class KLALBStateGUI3 extends XFrame { nogui.setSelected( kck.isNogui()); + // 加载设备名称 + String dname = kck.getDeviceName(); + deviceNameSet.setText(dname != null ? dname : ""); + + // 加载设备描述 + String ddesc = kck.getDeviceDescription(); + deviceDescriptionSet.setText(ddesc != null ? ddesc : ""); + // 加载IPv6地址 String vaddr = kck.getVirtualAddress(); addressFieldSet.setText(vaddr != null ? vaddr : ""); @@ -1461,6 +1530,10 @@ public class KLALBStateGUI3 extends XFrame { List dns = kck.getDNS(); dnsAreaSet.setText(listToStr(dns)); + // 加载额外路由 + List ers = kck.getExtraRoutes(); + extraRoutesSet.setText(listToStr2(ers)); + // 加载ASN Long vasn = kck.getVirtualASN(); asnFieldSet.setText(vasn != null ? vasn.toString() : ""); diff --git a/src/org/kne/cloud/network/klalb/ui/NetworkGraphPanel.java b/src/org/kne/cloud/network/klalb/ui/NetworkGraphPanel.java index ebf3f44..9a88786 100644 --- a/src/org/kne/cloud/network/klalb/ui/NetworkGraphPanel.java +++ b/src/org/kne/cloud/network/klalb/ui/NetworkGraphPanel.java @@ -47,7 +47,7 @@ public class NetworkGraphPanel extends GraphPanel { } public InetGraphNode(IPv6Address address, Color color, double x, double y, boolean ismarked) { - super(getText(address), color, x, y, ismarked); + super(getNodeText(address), color, x, y, ismarked); this.address=address; initign(); } @@ -137,17 +137,33 @@ public class NetworkGraphPanel extends GraphPanel { return address2.toCompressedString(); } + public void updateLabel() { + setText(getNodeText(address)); + } + public IPv6Address getAddress() { return address; } public void setAddress(IPv6Address address) { this.address = address; - super.setText(getText(address)); + super.setText(getNodeText(address)); } } + /** + * 节点标签:显示广播得知的设备名称(若有)+IP地址 + */ + private String getNodeText(IPv6Address address) { + StringBuilder sb=new StringBuilder(); + String dname=controller.getIpv6Router().getKlalbRouteProtol().getDeviceName(address); + if(dname!=null) + sb.append(dname).append('\n'); + sb.append(InetGraphNode.getText(address)); + return sb.toString(); + } + private double nsPerPixel=1000L; private class InetGraphEdgeGroup extends GraphEdgeGroup{ public InetGraphEdgeGroup(GraphNode nodeA, GraphNode nodeB) { @@ -178,6 +194,8 @@ public class NetworkGraphPanel extends GraphPanel { IPv6Address inet6Address = (IPv6Address) iterator.next(); if(!addr.containsKey(inet6Address)) { iterator.remove(); + }else { + ((InetGraphNode)getNodes().get(inet6Address)).updateLabel(); } } //System.out.println("------------------------------------"); diff --git a/src/org/kne/cloud/network/klalb/ui/NodeInformationPanel.java b/src/org/kne/cloud/network/klalb/ui/NodeInformationPanel.java index dba1cc1..e09549e 100644 --- a/src/org/kne/cloud/network/klalb/ui/NodeInformationPanel.java +++ b/src/org/kne/cloud/network/klalb/ui/NodeInformationPanel.java @@ -10,10 +10,12 @@ import java.util.List; import javax.swing.Icon; import javax.swing.ImageIcon; +import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; +import javax.swing.JTextArea; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; @@ -65,6 +67,27 @@ public class NodeInformationPanel extends JPanel { panel.setLayout(new BorderLayout(0, 0)); tabbedPane.addTab(UIEnv.getRsb().getString("overview"), null, panel, null); + JTextArea overviewArea = new JTextArea(); + overviewArea.setEditable(false); + overviewArea.setLineWrap(true); + overviewArea.setWrapStyleWord(true); + overviewArea.setFont(UIEnv.getFont().deriveFont(14.0f)); + 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); + if(dname!=null) { + sb.append('\n').append(UIEnv.getRsb().getString("devicename")).append(": ").append(dname).append('\n'); + } + if(address.equals(controller.getIpv6Router().getLocator().getAddress())&&controller.getConfigItem()!=null) { + String ddesc=controller.getConfigItem().getDeviceDescription(); + if(ddesc!=null&&!ddesc.isEmpty()) { + sb.append('\n').append(UIEnv.getRsb().getString("devicedescription")).append(":\n").append(ddesc).append('\n'); + } + } + overviewArea.setText(sb.toString()); + panel.add(new JScrollPane(overviewArea), BorderLayout.CENTER); + JPanel panel_1 = new JPanel(); panel_1.setLayout(new BorderLayout(0, 0)); panel_1.add(scrollPane); diff --git a/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java b/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java index db71a24..372a6cd 100644 --- a/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java +++ b/src/org/kne/cloud/network/srv6/KLALBRoutingProtocol.java @@ -545,6 +545,7 @@ public class KLALBRoutingProtocol extends Thread{ Listlinks=router.getLinkTabel(); Object[] nls=links.toArray(); RouterInfo ri=new RouterInfo(System.currentTimeMillis(),router.getLocator(),router.getASN()); + ri.setDeviceName(router.getDeviceName()); for(int i=0;i getAddresses() { return addresses; } + + /** + * 查询某地址广播的设备名称(未知返回null) + */ + public String getDeviceName(IPv6Address address) { + RouterInfo ri=netmap.get(address); + if(ri!=null) { + String dn=ri.getDeviceName(); + if(dn!=null&&!dn.isEmpty()) + return dn; + } + return null; + } public Map> getPaths() { return paths; } diff --git a/src/org/kne/cloud/network/srv6/RouterInfo.java b/src/org/kne/cloud/network/srv6/RouterInfo.java index ceffabd..ae46e1f 100644 --- a/src/org/kne/cloud/network/srv6/RouterInfo.java +++ b/src/org/kne/cloud/network/srv6/RouterInfo.java @@ -60,6 +60,7 @@ public class RouterInfo implements Serializable{ return Objects.equals(locator, other.locator) && Objects.equals(neighborAddresses, other.neighborAddresses); } private List neighborAddresses=new ArrayList<>(); + private String deviceName=""; // 设备名称(广播时携带,描述不广播) private long createTime; @@ -90,6 +91,14 @@ public class RouterInfo implements Serializable{ return neighborAddresses; } + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + public RouterInfo( long createTime,IPv6AddressGroup locator,long asn) { this.createTime = createTime; this.locator=locator; @@ -106,6 +115,7 @@ public class RouterInfo implements Serializable{ for( NeighborInfo neighborInfo :neighborAddresses) { neighborInfo.writeToStream(out); } + out.writeUTF(deviceName==null?"":deviceName); } protected void writeToChannel(WritableByteChannel dto) throws IOException { @@ -126,6 +136,7 @@ public class RouterInfo implements Serializable{ neighborAddresses.add(nif); } + deviceName=in.readUTF(); } } diff --git a/src/org/kne/cloud/network/srv6/SRv6Router.java b/src/org/kne/cloud/network/srv6/SRv6Router.java index 5653179..ea513ca 100644 --- a/src/org/kne/cloud/network/srv6/SRv6Router.java +++ b/src/org/kne/cloud/network/srv6/SRv6Router.java @@ -294,6 +294,15 @@ public class SRv6Router { private IPv6AddressGroup locator; // SRv6定位器 private long asn = new SecureRandom().nextLong(1, Long.MAX_VALUE); // 自治系统号 + private volatile String deviceName; // 设备名称(随路由信息广播) + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } public IPv6AddressGroup getLocator() { return locator;