feat: 新增设备信息与额外路由设置,支持设备名广播及TUN显式禁用

- 设置页新增设备名称(单行)、设备描述(多行)、额外路由(CIDR列表)设置项
- RouterInfo 广播携带 deviceName,并在拓扑图节点与节点概览中展示;deviceDescription 保持本地概览显示
- 拓扑图节点标签支持多行文本绘制
- 节点概览面板新增 IP 地址及设备详情展示
- 支持将 TUNName 设为 null/"null"/空字符串时完全跳过 Wintun 虚拟网卡创建
- .classpath 容器改为标准 JavaSE-25 执行环境以同时兼容 JDK 25 与 26
- 新增 AGENTS.md 与 VS Code 调试及运行配置

BREAKING CHANGE: RouterInfo 在序列化末尾追加了 deviceName 字段(writeUTF),新旧版本节点混连时路由协议解析异常,需同步升级
This commit is contained in:
2026-08-21 23:34:41 +08:00
parent f0efa6d041
commit 455139dfe9
18 changed files with 335 additions and 12 deletions
+1 -1
View File
@@ -24,7 +24,7 @@
<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/jdk-26.0.1">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25">
<attributes>
<attribute name="module" value="true"/>
</attributes>
+11
View File
@@ -14,4 +14,15 @@
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
<filteredResources>
<filter>
<id>1787317094049</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>
+27
View File
@@ -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"
}
]
}
+9
View File
@@ -0,0 +1,9 @@
{
"java.configuration.runtimes": [
{
"name": "JavaSE-25",
"path": "C:\\Program Files\\Eclipse Adoptium\\jdk-25.0.4.7-hotspot",
"default": true
}
]
}
+55
View File
@@ -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.
+4 -1
View File
@@ -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"
},
+4
View File
@@ -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
+4
View File
@@ -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监听端口:非法输入
@@ -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);
@@ -19,6 +19,7 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
private List<MultiProtocolSocketAddress>LineTable=new ArrayList<>();
private List<MultiProtocolSocketAddress>ConnectLineTable=new ArrayList<>();
private List<MultiProtocolSocketAddress>ntpServerTable=new ArrayList<>();
private List<String>ExtraRoutes=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<String> networkInterfaceExcepts) {
NetworkInterfaceExcepts = networkInterfaceExcepts;
}
@@ -193,6 +212,14 @@ public class KLALBControllerConfigItem extends KLALBConfigItem {
this.ntpServerTable = ntpServerTable;
}
public List<String> getExtraRoutes() {
return ExtraRoutes;
}
public void setExtraRoutes(List<String> 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);
}
}
@@ -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)));
}
@@ -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() {
@@ -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<PerformanceStrategyItem> 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<String> 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<InetAddress> dns = kck.getDNS();
dnsAreaSet.setText(listToStr(dns));
// 加载额外路由
List<String> ers = kck.getExtraRoutes();
extraRoutesSet.setText(listToStr2(ers));
// 加载ASN
Long vasn = kck.getVirtualASN();
asnFieldSet.setText(vasn != null ? vasn.toString() : "");
@@ -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("------------------------------------");
@@ -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);
@@ -545,6 +545,7 @@ public class KLALBRoutingProtocol extends Thread{
List<IPv6NetworkLink>links=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<nls.length;i++) {
IPv6NetworkLink nl=(IPv6NetworkLink) nls[i];
if((!nl.isLoopBack())&&nl.isUp()) {
@@ -595,6 +596,19 @@ public class KLALBRoutingProtocol extends Thread{
public Map<IPv6Address, Long> 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<IPv6Address, List<LinkDirection>> getPaths() {
return paths;
}
@@ -60,6 +60,7 @@ public class RouterInfo implements Serializable{
return Objects.equals(locator, other.locator) && Objects.equals(neighborAddresses, other.neighborAddresses);
}
private List<NeighborInfo> 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();
}
}
@@ -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;