12 Commits
Author SHA1 Message Date
KNEMC 3b73e2b613 减小体积 2026-11-02 16:10:32 +08:00
KNEMC ec51e5a778 修复Kperf测速工具仪表盘显示bug,优化Kperf缓存命中率 2026-10-31 17:47:08 +08:00
KNEMC c0e73bce55 内存优化,减轻GC压力 2026-10-29 13:40:01 +08:00
KNEMC b898e4c5be 修复了SRH插入失败导致无法转发的bug 2026-10-21 14:24:32 +08:00
KNEMC 61bc066f82 添加README.md 2026-10-07 12:41:52 +08:00
KNEMC 7f46c1b8c9 修复滑动窗口出现负数的bug
修复拥塞算法RTT延迟为0的bug
2026-10-07 12:35:12 +08:00
KNEMC 156d74bbe3 修复滑动窗口出现负数的bug 2026-10-07 12:34:23 +08:00
KNEMC 862b860020 修复延迟基线bug
Timer改成线程池,修复系统时间改变导致定时任务无法执行的bug
2026-09-29 20:10:57 +08:00
KNEMC 100fad7d18 cmt 2026-09-29 10:49:51 +08:00
KNEMC 6d6a199728 把NTP从平均数改成中位数,防止极端值干扰 2026-09-01 15:36:15 +08:00
KNEMC 21b975676d 现在当目的地址是直接邻居(不需要转发)时,不插入SRv6扩展头节约带宽 2026-09-01 10:21:49 +08:00
KNEMC 2c111770b3 整理SRv6Router代码,修bug,增加SRHInsert虚链路 2026-08-31 19:07:53 +08:00
68 changed files with 2798 additions and 1089 deletions
+3 -18
View File
@@ -2,34 +2,19 @@
<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/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/KNEOptimize.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/jctools-core-4.0.6.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="lib" path="lib/jctools-core-4.0.6-sources.jar"/>
<classpathentry kind="lib" path="lib/KNElib1.0.jar"/>
<classpathentry kind="lib" path="lib/JavaTUN0.3.jar"/>
<classpathentry kind="lib" path="lib/KNEOptimize.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.jar"/>
<classpathentry kind="lib" path="lib/jfreechart-1.5.3-javadoc.jar"/>
<classpathentry kind="lib" path="lib/jfreechart-1.5.3-sources.jar"/> <classpathentry kind="lib" path="lib/jfreechart-1.5.3-sources.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>
Generated
+1
View File
@@ -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>
Binary file not shown.
+1348
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
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.
+6
View File
@@ -117,3 +117,9 @@ enablewebapi=Enable Web API
weblistenaddr=Web API listen address weblistenaddr=Web API listen address
invaildweblistenaddr=Invalid Web API listen address invaildweblistenaddr=Invalid Web API listen address
enabletun=Enable TUN adapter enabletun=Enable TUN adapter
congestionmonitor=Congestion control monitor
rttbaseline=RTT baseline
rtt=RTT
rttmax=RTT max
rttmin=RTT min
rto=RTO
+6
View File
@@ -117,3 +117,9 @@ enablewebapi=启用 Web API
weblistenaddr=Web API 监听地址:端口 weblistenaddr=Web API 监听地址:端口
invaildweblistenaddr=无效的 Web API 监听地址:端口 invaildweblistenaddr=无效的 Web API 监听地址:端口
enabletun=启用TUN虚拟网卡 enabletun=启用TUN虚拟网卡
congestionmonitor=拥塞控制监视器
rttbaseline=往返延迟基线
rtt=往返延迟
rttmax=往返延迟上限
rttmin=往返延迟下限
rto=重传超时
@@ -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.");
}
}
@@ -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();
} }
@@ -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();
@@ -56,8 +61,7 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
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,65 +165,15 @@ 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) {
Collection<SendItem<V>> vals = sendMap.values();
for (Iterator<SendItem<V>> iterator = vals.iterator(); iterator.hasNext();) {
SendItem<V> sitm = (SendItem<V>) iterator.next();
long current = System.nanoTime();
if (current - sitm.getSendtime() > algorithm.getRTO()) {
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);
}
}
try { try {
Thread.sleep(2); if (closed) {
} catch (InterruptedException e) { checkerTask.cancel(false);
e.printStackTrace();
}
}
// 清理资源 // 清理资源
if (closingConsumer != null) { if (closingConsumer != null) {
for (SendItem<V> item : sendMap.values()) { for (SendItem<V> item : sendMap.values()) {
@@ -229,6 +182,42 @@ public class SendPacketSlidingWindow<K, V extends NetworkPacket> implements Clos
} }
sendMap.clear(); sendMap.clear();
sendWindowUsed.set(0); 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);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
} }
} }
@@ -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,29 +74,20 @@ 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(); long curr = System.nanoTime();
// 每个RTT周期调整一次窗口(使用当前估计的RTT) // 每个RTT周期调整一次窗口(使用当前估计的RTT)
if (curr - RTTstartTime > Math.max(BIAS, 2 * RTTMin)) { if (curr - RTTstartTime > Math.max(BIAS, 2 * RTTMin)) {
rttEstimator.update();
RTTMin = rttEstimator.getBaseRTT();
long RTTCountx = RTTCount; long RTTCountx = RTTCount;
if (RTTCountx > 0) { if (RTTCountx > 0) {
long currentRTT = RTTTotal / RTTCountx; long currentRTT = RTTTotal / RTTCountx;
@@ -206,24 +104,23 @@ public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCong
// 2. 基于比值的窗口调整(取代原来的基于差值的调整) // 2. 基于比值的窗口调整(取代原来的基于差值的调整)
if (delayRatio > delayUpperBound) { if (delayRatio > delayUpperBound) {
// 时延过高:减小窗口,减少幅度与超标程度成正比 // 时延过高:减小窗口,减少幅度与超标程度成正比
window2 -= 4096; window2 = window2 - 4096;
} else if (delayRatio < delayLowerBound) { } else if (delayRatio < delayLowerBound) {
// 时延过低:增大窗口,增加幅度与低于目标程度成正比 // 时延过低:增大窗口,增加幅度与低于目标程度成正比
window2 += 4096; window2 = window2 + 4096;
} else { } else {
//window2=window2+4096
} }
// =================================================== // ===================================================
updateWindowSize(); updateWindowSize();
RTTstartTime = curr; RTTstartTime = curr;
}
}finally{
slock.unlock();
} }
} }
@@ -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;
}
} }
@@ -15,11 +15,18 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
private SRv6Router srv6Router; private SRv6Router srv6Router;
private final boolean loopback; private final boolean loopback;
private final boolean filter;
public AbstractIPv6NetworkLink(boolean loopback) { public AbstractIPv6NetworkLink(boolean loopback) {
super(); super();
this.loopback = loopback; 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() {
@@ -63,6 +70,8 @@ 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;
@@ -73,6 +82,14 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
return loopback; return loopback;
} }
public Supplier<Long> getCostSupplier() {
return costSupplier;
}
public void setCostSupplier(Supplier<Long> costSupplier) {
this.costSupplier = costSupplier;
}
@Override @Override
public List<RouteItem> getRouteItems() { public List<RouteItem> getRouteItems() {
List<RouteItem> rlist = new ArrayList<>(); List<RouteItem> rlist = new ArrayList<>();
@@ -86,16 +103,21 @@ public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) { for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
Neighbor addresses = (Neighbor) iteratorx.next(); Neighbor addresses = (Neighbor) iteratorx.next();
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128), RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
addresses.getAddress().getAddress(), this,RouteItem.SRv6_ENDXSID, 0, 128, null, "D"); addresses.getAddress().getAddress(), this,RouteItem.SRv6_ENDXSID, 0, 128, costSupplier, "D");
rlist.add(ri); rlist.add(ri);
RouteItem ris = new RouteItem(addresses.getLocator(), RouteItem ris = new RouteItem(addresses.getLocator(),
addresses.getLocator().getAddress(), this, RouteItem.SRv6_ENDSID, 13, 128, addresses.getLocator().getAddress(), this, RouteItem.SRv6_ENDSID, 13, 128,
null, "D"); costSupplier, "D");
rlist.add(ris); rlist.add(ris);
} }
} }
return rlist; 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;
} }
@@ -7,6 +7,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
public static final String DIRECT="Direct"; public static final String DIRECT="Direct";
public static final String SRv6_ENDSID="SRv6 ENDSID"; public static final String SRv6_ENDSID="SRv6 ENDSID";
public static final String SRv6_ENDXSID="SRv6 ENDXSID"; 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;
@@ -39,7 +40,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
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) { 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;
@@ -50,7 +51,7 @@ public class RouteItem implements Comparable<RouteItem>,Cloneable{
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) { 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;
@@ -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));
@@ -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() {
@@ -306,7 +286,7 @@ public class KLALBController {
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() {
@@ -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());
@@ -653,8 +634,7 @@ public class KLALBController {
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);
@@ -686,7 +666,7 @@ 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() {
@@ -718,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");
@@ -734,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() {
@@ -753,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();
},1,1,TimeUnit.MILLISECONDS);
KLALBScheduler.getScheduler().scheduleWithFixedDelay( ()->{
datatMonitor.update(); datatMonitor.update();
try { },1,1,TimeUnit.MILLISECONDS);
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
loadSRv6ProtocolStack(selfg, enableVirtualAdapter); loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
loadController(); loadController();
} }
@@ -856,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() {
@@ -869,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() {
@@ -880,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) {
@@ -13,6 +13,8 @@ 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;
@@ -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;
@@ -149,6 +142,7 @@ public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implement
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) {
@@ -164,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));
} }
@@ -283,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) {
@@ -568,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();
}
} }
@@ -753,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();
} }
@@ -896,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);
@@ -944,28 +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()) {
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, CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(), status, algorithm::getRTO), "D");
rlist.add(ri);
if (addresses.getLocator() != null) {
RouteItem ris = new RouteItem(addresses.getLocator(), addresses.getLocator().getAddress(), this,
RouteItem.SRv6_ENDSID, 13, 128, CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(), status, algorithm::getRTO), "D");
rlist.add(ris);
}
}
}
return rlist;
}*/
@Override @Override
public void setCongressCondition(Lock lock, Condition condition) { public void setCongressCondition(Lock lock, Condition condition) {
@@ -973,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);
}
} }
@@ -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;
}
}
@@ -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,39 +118,43 @@ 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;
// 3. 发送
writableChannel.write(new ByteBuffer[] {szeWrite, kp}); 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 = SIZE_READ_BUFFER.get();
szeRead.clear();
szeRead.limit(4);
ByteBuffer szeRead=NetworkPacket.bufferAllocator.allocate(4);
timeoutTimer = System.nanoTime(); timeoutTimer = System.nanoTime();
timerenabled = true; timerenabled = true;
ByteBuffer kp; ByteBuffer kp;
szeRead.clear();
szeRead.limit(4);
//szeRead.clear();
try { try {
// 2. 读取长度头
KNEChannels.readFully(readableChannel, szeRead); KNEChannels.readFully(readableChannel, szeRead);
szeRead.flip(); szeRead.flip();
int size = szeRead.getInt(0); int size = szeRead.getInt(0);
// 3. 分配真正的数据区(这里如果是高频,建议后续也可以池化,不过现在是按需大小分配)
kp = NetworkPacket.bufferAllocator.allocate(size); kp = NetworkPacket.bufferAllocator.allocate(size);
kp.limit(size); kp.limit(size);
KNEChannels.readFully(readableChannel, kp); KNEChannels.readFully(readableChannel, kp);
@@ -7,8 +7,8 @@ import java.io.IOException;
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.*;
@@ -37,8 +37,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; // 系统托盘
@@ -705,10 +704,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);
} }
@@ -1322,9 +1317,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()) {
@@ -1382,28 +1377,26 @@ 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()) {
@@ -1415,8 +1408,7 @@ public class KLALBStateGUI3 extends XFrame {
graph.revalidate(); graph.revalidate();
} }
} }
}; }, 1000, 1000,TimeUnit.MILLISECONDS);
t.scheduleAtFixedRate(tsk5, 1000, 1000);
} }
/** /**
@@ -1425,29 +1417,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();
if (Double.isFinite(outload)) {
upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getOutSpeed()) + "/s"); upSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().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 = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax(); double inload = kc.getLinkMonitor().getInSpeed() * 100.0 / kc.getLinkMonitor().getInSpeedMax();
if (Double.isFinite(inload)) {
downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s"); downSpeedText.setLabel(KLALBUtils.convertIBUint(kc.getLinkMonitor().getInSpeed()) + "/s");
if (Double.isFinite(inload)) {
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();
if (Double.isFinite(outPPSload)) {
upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS"); upPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getOutPPS()) + "PPS");
if (Double.isFinite(outPPSload)) {
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();
if (Double.isFinite(inPPSload)) {
downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS"); downPPSText.setLabel(KLALBUtils.convertUintDefalut(kc.getLinkMonitor().getInPPS()) + "PPS");
if (Double.isFinite(inPPSload)) {
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));
} }
@@ -1479,29 +1471,29 @@ 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;
if (Double.isFinite(backplaneTimev)) {
backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s"); backplaneDelayText.setLabel(KLALBUtils.convertUintNanoDefalut(router.getBackplaneTime()) + "s");
if (Double.isFinite(backplaneTimev)) {
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();
if (Double.isFinite(backplanePPSv)) {
backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS"); backplanePPSText.setLabel(KLALBUtils.convertUintDefalut(router.getBackplanePPS()) + "PPS");
if (Double.isFinite(backplanePPSv)) {
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 ;
if (Double.isFinite(backplaneECNv)) {
backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%"); backplaneECNRateText.setLabel(String.format("%.1f",backplaneECNv) + "%");
if (Double.isFinite(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 ;
if (Double.isFinite(backplaneLossv)) {
backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%"); backplaneLossRateText.setLabel(String.format("%.1f",backplaneLossv) + "%");
if (Double.isFinite(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));
} }
} }
@@ -1764,7 +1756,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);
@@ -45,7 +45,6 @@ public class KperfGUI extends XFrame{
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 +53,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;
@@ -70,10 +69,6 @@ public class KperfGUI extends XFrame{
private TimerTask tsk; private TimerTask 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) {
@@ -521,9 +516,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);
@@ -538,26 +530,26 @@ public class KperfGUI extends XFrame{
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(); double inload = monitor.getInSpeed() * 100.0 / monitor.getInSpeedMax();
if (Double.isFinite(inload)) {
downSpeedText.setLabel(KLALBUtils.convertIBUint(monitor.getInSpeed()) + "/s"); 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)); downSpeed.setValue(Math.min(downSpeed.getValue().doubleValue() * 0.98 + inload * 0.02, 101.0));
} }
double outPPSload = monitor.getOutPPS() * 100.0 / monitor.getOutPPSMax(); double outPPSload = monitor.getOutPPS() * 100.0 / monitor.getOutPPSMax();
if (Double.isFinite(outPPSload)) {
upPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getOutPPS()) + "PPS"); 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)); upPPS.setValue(Math.min(upPPS.getValue().doubleValue() * 0.98 + outPPSload * 0.02, 101.0));
} }
double inPPSload = monitor.getInPPS() * 100.0 / monitor.getInPPSMax(); double inPPSload = monitor.getInPPS() * 100.0 / monitor.getInPPSMax();
if (Double.isFinite(inPPSload)) {
downPPSText.setLabel(KLALBUtils.convertUintDefalut(monitor.getInPPS()) + "PPS"); 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)); downPPS.setValue(Math.min(downPPS.getValue().doubleValue() * 0.98 + inPPSload * 0.02, 101.0));
} }
} }
@@ -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);
} }
@@ -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,13 +236,16 @@ 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);
}else if(!sendMap.isCongestion()){
try { try {
if (olock != null) if (olock != null)
olock.lock(); olock.lock();
try { try {
if(!sendMap.isCongestion()) {
flush0(); flush0();
}
} finally { } finally {
if (olock != null) if (olock != null)
olock.unlock(); olock.unlock();
@@ -253,8 +254,9 @@ public class KLTPOutputStream extends OutputStream implements KLTPPacketConsumer
ioe.set(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,6 +311,17 @@ private String name;
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
return 0; return 0;
} }
@Override
public long calculateMinDelay(long timeWindowNs) {
return 0;
}
@Override
public long calculateMinDelay(Long128 currentTime, long timeWindowNs) {
return 0;
}
@Override @Override
public TimestampMonitorValue getRecentDelayEntry() { public TimestampMonitorValue getRecentDelayEntry() {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
@@ -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,6 +150,10 @@ public interface TimestampMonitor<K> {
long getRecentDelay(); long getRecentDelay();
long calculateMinDelay(long timeWindowNs);
long calculateMinDelay(Long128 currentTime, long timeWindowNs);
TimestampMonitorValue getRecentDelayEntry(); 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);
+6 -27
View File
@@ -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); }
*/
}
} }
+13 -30
View File
@@ -4,17 +4,15 @@ 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.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;
@@ -79,25 +77,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 +119,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 +130,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 +145,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);
} }
@@ -303,9 +295,6 @@ public class Kperf implements Runnable{
tlock.unpark(); tlock.unpark();
updateUsedTime() ;
if(reports!=null)
reports.updateDial(monitor);
break; break;
case KLALBPacket.TESTN: case KLALBPacket.TESTN:
break; break;
@@ -330,12 +319,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 +420,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);
+46 -32
View File
@@ -1,16 +1,11 @@
package org.kne.cloud.network.perf; package org.kne.cloud.network.perf;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import org.kne.cloud.network.ByteBufferAllocator;
import org.kne.cloud.network.NetworkPacket; import org.kne.cloud.network.NetworkPacket;
import org.kne.cloud.network.klalb.KLALBPacket; import org.kne.cloud.network.klalb.KLALBPacket;
@@ -18,56 +13,75 @@ public class TESTNPacket extends KLALBPacket {
private static final int HEADER_LENGTH = 3; private static final int HEADER_LENGTH = 3;
private ByteBuffer dataBuffer;//=NetworkPacket.databufferpool_65535.borrow(); // 核心:一个线程私有的 65535 字节大缓存,生命周期与线程同寿
private static final ThreadLocal<ByteBuffer> BENCH_BUFFER =
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
// 不再持有 ByteBuffer,只记录长度
private int payloadLength;
@Override @Override
public long getTotalLength() { public long getTotalLength() {
return HEADER_LENGTH+dataBuffer.limit(); return HEADER_LENGTH + payloadLength;
} }
// 发送端构造
public TESTNPacket(int limit) { public TESTNPacket(int limit) {
super(TESTN, HEADER_LENGTH); super(TESTN, HEADER_LENGTH);
//dataBuffer.limit(limit); this.payloadLength = limit;
dataBuffer=NetworkPacket.bufferAllocator.allocate(limit);
} }
// 接收端构造(从已有的 ByteBuffer 解析)
public TESTNPacket(ByteBuffer bb) {
public ByteBuffer getDataBuffer() { super(bb, HEADER_LENGTH);
return dataBuffer; this.payloadLength = klalbHeader.getChar(1);
} }
public int getPayloadLength() {
return payloadLength;
}
@Override @Override
public void writeToChannel(WritableByteChannel dto) throws IOException { public void writeToChannel(WritableByteChannel dto) throws IOException {
klalbHeader.putChar(1, (char) dataBuffer.limit()); // 1. 写入包头(包含 payloadLength)
klalbHeader.putChar(1, (char) payloadLength);
super.writeToChannel(dto); super.writeToChannel(dto);
//System.out.println(dataBuffer);
dto.write(dataBuffer.slice(0, dataBuffer.limit())); // 2. 如果有 payload,借用 ThreadLocal 缓冲区并写出去
if (payloadLength > 0) {
ByteBuffer buf = BENCH_BUFFER.get();
buf.clear();
buf.limit(payloadLength); // 限制到指定长度
// 直接写出,里面的数据是上一次残留的或者全 0,对于烤机无所谓
dto.write(buf);
}
} }
@Override @Override
public void readFromChannel(ReadableByteChannel din) throws IOException { public void readFromChannel(ReadableByteChannel din) throws IOException {
// 1. 读包头
super.readFromChannel(din); super.readFromChannel(din);
int limit=klalbHeader.getChar(1); this.payloadLength = klalbHeader.getChar(1);
dataBuffer=NetworkPacket.bufferAllocator.allocate(limit);
while(dataBuffer.hasRemaining()){
if(din.read(dataBuffer)==-1) {
throw new EOFException();
}
}
dataBuffer.flip();
}
public TESTNPacket(ByteBuffer bb) { // 2. 如果有 payload,借用缓冲区接收数据
super(bb,HEADER_LENGTH); if (payloadLength > 0) {
} ByteBuffer buf = BENCH_BUFFER.get();
buf.clear();
buf.limit(payloadLength);
// 循环读满(使用你现有的 KNEChannels 工具或手动循环)
while (buf.hasRemaining()) {
if (din.read(buf) == -1) {
throw new EOFException("连接提前断开,未能读满 TESTN 载荷");
}
}
// 数据读完直接丢弃,缓冲区不保存,下一次 clear() 时会自动覆盖
}
}
@Override @Override
public String toString() { public String toString() {
return "TESTN["+dataBuffer.limit()+"]"; return "TESTN[" + payloadLength + "]";
} }
} }
@@ -9,6 +9,7 @@ import java.net.Inet6Address;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.SocketException; import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -35,6 +36,7 @@ import org.kne.cloud.network.monitor.MonitorData;
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl; import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData; import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData;
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl; import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
import org.kne.io.KNEChannels;
import org.kne.membandboost.MembandBoost; import org.kne.membandboost.MembandBoost;
public class KLALBRoutingProtocol extends Thread{ public class KLALBRoutingProtocol extends Thread{
@@ -211,20 +213,15 @@ public class KLALBRoutingProtocol extends Thread{
while(true) { while(true) {
try { try {
byte[]ca=MembandBoost.allocateUninitializedByteArray(65535); KLALBRoutingProtocolPacket kp=receivePacket();
DatagramPacket dgp=new DatagramPacket(ca, ca.length);
ds.receive(dgp);
//System.out.println(Arrays.toString( Arrays.copyOf( dgp.getData(),dgp.getLength())));
ByteArrayInputStream bi=new ByteArrayInputStream(dgp.getData(),0,dgp.getLength());
KLALBRoutingProtocolPacket kp=KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(Channels.newChannel(bi));
switch(kp.getType()) { switch(kp.getType()) {
case KLALBRoutingProtocolPacket.RINFO_REQ: case KLALBRoutingProtocolPacket.RINFO_REQ:
RouterInfo rifr=netmap.get(router.getLocator().getAddress()); RouterInfo rifr=netmap.get(router.getLocator().getAddress());
if(debug) if(debug)
System.out.println("get Request from:"+dgp.getSocketAddress()); System.out.println("get Request from:"+kp.getFrom());
if(rifr!=null) { if(rifr!=null) {
writePacket( new RouterInfoPacket( rifr,false,-1), dgp.getSocketAddress()); writePacket( new RouterInfoPacket( rifr,false,-1), kp.getFrom());
if(debug) if(debug)
System.out.println("response router info:"+rifr); System.out.println("response router info:"+rifr);
}else { }else {
@@ -246,7 +243,7 @@ public class KLALBRoutingProtocol extends Thread{
netmap.put(rif.getLocator().getAddress(), rif); netmap.put(rif.getLocator().getAddress(), rif);
noticeUpdate(); noticeUpdate();
if(rifp.isFlood()) { if(rifp.isFlood()) {
floodPacket( dgp.getSocketAddress(), rifp); floodPacket( kp.getFrom(), rifp);
} }
@@ -259,7 +256,7 @@ public class KLALBRoutingProtocol extends Thread{
break; break;
case KLALBRoutingProtocolPacket.JSON_DATA: case KLALBRoutingProtocolPacket.JSON_DATA:
JsonDataPacket data=(JsonDataPacket) kp; JsonDataPacket data=(JsonDataPacket) kp;
receivers.forEach((v)->{v.accept(dgp.getSocketAddress(),data);}); receivers.forEach((v)->{v.accept(kp.getFrom(),data);});
break; break;
default: default:
break; break;
@@ -276,7 +273,32 @@ public class KLALBRoutingProtocol extends Thread{
} }
} }
} }
private static final ThreadLocal<ByteBuffer> LSDB_RX_BUFFER =
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
private KLALBRoutingProtocolPacket receivePacket() throws IOException {
// 2. 获取并重置缓冲区
ByteBuffer bbf = LSDB_RX_BUFFER.get();
bbf.clear();
// 3. 构造 DatagramPacket(注意这里要传底层 array 和 capacity)
DatagramPacket dgp = new DatagramPacket(bbf.array(), bbf.capacity());
// 4. 阻塞接收
ds.receive(dgp);
// 5. 限制缓冲区范围到实际收到的长度
bbf.limit(dgp.getLength());
bbf.position(0);
// 6. 直接用 KNEChannels 包装 ByteBuffer,避免 ByteArrayInputStream
KLALBRoutingProtocolPacket kp = KLALBRoutingProtocolPacket.readKLALBPacketFromChannel(
KNEChannels.newReadableChannel(bbf)
);
if(kp!=null)
kp.setFrom(dgp.getSocketAddress());
return kp;
}
private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException { private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException {
long asn=rifp.getASN(); long asn=rifp.getASN();
List<Neighbor>ln= router.getNeighbors(); List<Neighbor>ln= router.getNeighbors();
@@ -304,13 +326,27 @@ public class KLALBRoutingProtocol extends Thread{
public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException { public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException {
writePacket(pkt,dest); writePacket(pkt,dest);
} }
// 1. 在类成员变量处定义一个 64KB 的 ThreadLocal 缓冲区
// 注意:这里依然使用 65535,因为你说 LSDB 同步可能需要这么大
private static final ThreadLocal<ByteBuffer> LSDB_TX_BUFFER =
ThreadLocal.withInitial(() -> ByteBuffer.allocate(65535));
private void writePacket(KLALBRoutingProtocolPacket pkt, SocketAddress dest) throws IOException { private void writePacket(KLALBRoutingProtocolPacket pkt, SocketAddress dest) throws IOException {
ByteArrayOutputStream bos=new ByteArrayOutputStream(65535); // 2. 从 ThreadLocal 获取,并清空状态
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(Channels.newChannel(bos),pkt); ByteBuffer bbf = LSDB_TX_BUFFER.get();
byte[]to=bos.toByteArray(); bbf.clear();
DatagramPacket dgpx=new DatagramPacket(to,to.length);
// 3. 使用 KNEChannels 绑定到 ByteBuffer,直接写入
// 这避免了 ByteArrayOutputStream 内部的动态扩容和拷贝
KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(KNEChannels.newWritableChannel(bbf), pkt);
// 4. 翻转,准备读取数据
bbf.flip();
// 5. 直接拿底层的 byte[] 和真实的 limit 发送
DatagramPacket dgpx = new DatagramPacket(bbf.array(), bbf.limit());
dgpx.setSocketAddress(dest); dgpx.setSocketAddress(dest);
sendLock.lock(); sendLock.lock();
try { try {
ds.send(dgpx); ds.send(dgpx);
@@ -4,6 +4,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
@@ -133,4 +134,11 @@ public abstract class KLALBRoutingProtocolPacket extends NetworkPacket {
public static void writeKLALBPacketToChannel(WritableByteChannel writableByteChannel,KLALBRoutingProtocolPacket klb) throws IOException { public static void writeKLALBPacketToChannel(WritableByteChannel writableByteChannel,KLALBRoutingProtocolPacket klb) throws IOException {
klb.writeToChannel(writableByteChannel); klb.writeToChannel(writableByteChannel);
} }
private transient SocketAddress from;
public void setFrom(SocketAddress from) {
this.from=from;
}
public SocketAddress getFrom(){
return from;
}
} }
@@ -0,0 +1,51 @@
package org.kne.cloud.network.srv6;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.kne.cloud.network.ipv6.*;
public class SRHInsertNetworkLink extends AbstractIPv6NetworkLink {
private IPv6AddressGroup ipgroup;
public SRHInsertNetworkLink(SRv6Router sRv6Router,IPv6AddressGroup ipgroup) {
super(false,true);
setSRv6Router(sRv6Router);
this.ipgroup=ipgroup;
}
@Override
public List<IPv6AddressGroup> getAddressGroups() {
return new ArrayList<>();
}
@Override
public List<Neighbor> getNeighborsInfo() {
return new ArrayList<>();
}
@Override
public void sendPacket(IPv6Packet pack, IPv6Address inet6Address) throws IOException {
if(getSrv6Router().insertSRHeader( pack)) {
getSrv6Router().insertHeaderAndRoutePacket(null, pack);
}
}
@Override
public List<RouteItem> getRouteItems() {
return List.of(new RouteItem(ipgroup, null, this, RouteItem.KLALB_SRv6, 30, 0,"G"));
}
@Override
public String getName() {
return "SRHInsertNetworkLink";
}
@Override
public boolean isUp() {
return true;
}
}
+74 -107
View File
@@ -12,11 +12,11 @@ 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.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@@ -45,12 +45,13 @@ import org.kne.cloud.network.ipv6.PadNHopByHopTLV;
import org.kne.cloud.network.ipv6.PostcardEntry; import org.kne.cloud.network.ipv6.PostcardEntry;
import org.kne.cloud.network.ipv6.RouteItem; import org.kne.cloud.network.ipv6.RouteItem;
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.klalb.KLALBUtils; import org.kne.cloud.network.klalb.KLALBUtils;
import org.kne.cloud.network.klalb.PerformanceStrategy; import org.kne.cloud.network.klalb.PerformanceStrategy;
import org.kne.cloud.network.klalb.ui.PerformanceStrategyItem; import org.kne.cloud.network.klalb.ui.PerformanceStrategyItem;
import org.kne.concurrent.HighPerformanceExecutor2; import org.kne.concurrent.HighPerformanceExecutor2;
import org.kne.concurrent.TimeoutConcurrentHashMap; import org.kne.concurrent.TimeoutConcurrentHashMap;
import org.pcap4j.packet.IllegalRawDataException; import org.kne.io.KNEChannels;
import com.google.gson.internal.Pair; import com.google.gson.internal.Pair;
@@ -60,7 +61,7 @@ public class SRv6Router {
// public static final int MTU = 16384; // public static final int MTU = 16384;
public static final int MTU = 16384; // 最大传输单元 public static final int MTU = 16384; // 最大传输单元
public static final int MAX_REROUTE_COUNT = 2;// 1 // 最大重路由次数 public static final int MAX_REROUTE_COUNT = 1;// 最大重路由次数
private static final int IPv6_BITS = 128; // IPv6地址位数 private static final int IPv6_BITS = 128; // IPv6地址位数
@@ -104,7 +105,7 @@ public class SRv6Router {
// 环回网络链路 // 环回网络链路
private final LoopbackIPv6NetworkLink inLoopBack; private final LoopbackIPv6NetworkLink inLoopBack;
private final SRHInsertNetworkLink srhInserter;
// 获取路由表 // 获取路由表
public List<RouteItem> getRouteTabel() { public List<RouteItem> getRouteTabel() {
return routeTabel; return routeTabel;
@@ -121,7 +122,7 @@ public class SRv6Router {
@Override @Override
public void accept(IPv6Packet t) { public void accept(IPv6Packet t) {
// HighPerformanceExecutor.defaultExecutor.execute(() -> { // HighPerformanceExecutor.defaultExecutor.execute(() -> {
routePacket(null, t, true); // 执行重路由 routePacket(null, t); // 执行重路由
// }); // });
} }
}; };
@@ -142,21 +143,11 @@ public class SRv6Router {
if (oamtlv == null) if (oamtlv == null)
return true; return true;
boolean bool = unduplicateSet.add(oamtlv.getUUID()); boolean bool = unduplicateSet.add(oamtlv.getUUID());
// System.out.println(bool);
return bool; return bool;
} }
// 默认接收处理器
/*
* private BiConsumer<IPv6NetworkLink,IPv6Packet> defaultReceive = new
* BiConsumer<IPv6NetworkLink,IPv6Packet>() {
*
* @Override public void accept(IPv6NetworkLink link,IPv6Packet t) { //
* HighPerformanceExecutor.defaultExecutor.execute(() -> { if(unduplicate(t)) {
* routePacket(t); // 执行路由 t.putTimePassport("routed"); // 标记路由时间点 } // }); } };
*/
// SRH接收处理器 // 接收处理器
private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> srhReceive = new BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>>() { private BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>> receiveConsumer = new BiConsumer<IPv6NetworkLink, Supplier<IPv6Packet>>() {
@Override @Override
public void accept(IPv6NetworkLink link, Supplier<IPv6Packet> pack) { public void accept(IPv6NetworkLink link, Supplier<IPv6Packet> pack) {
@@ -213,34 +204,19 @@ public class SRv6Router {
srListeners.remove(listener); srListeners.remove(listener);
} }
public void sortRouteTabel() { public void sortRouteTabel() {
List<Map<IPv6Address, List<RouteItem>>> routeTabel1x = routeTabel1;
// 构建前缀长度索引的路由表
List<Map<IPv6Address, List<RouteItem>>> routeTabel1x = new ArrayList<Map<IPv6Address, List<RouteItem>>>(
IPv6_BITS + 1);
for (int i = 0; i < IPv6_BITS + 1; i++) {
routeTabel1x.add(new HashMap<IPv6Address, List<RouteItem>>(1024, 0.5f));
}
List<RouteItem> routeTabel0x=routeTable0;
// 按前缀长度组织路由表
for (RouteItem item : routeTabel0x) {
IPv6AddressGroup iag = item.getDestination();
Map<IPv6Address, List<RouteItem>> map = routeTabel1x.get(iag.getPrefixLength());
List<RouteItem> newlist = new ArrayList<RouteItem>();
List<RouteItem> oldlist = map.putIfAbsent(iag.getAddress(), newlist);
if (oldlist == null) {
oldlist = newlist;
}
oldlist.add(item);
}
for (Map<IPv6Address, List<RouteItem>> map : routeTabel1x) { for (Map<IPv6Address, List<RouteItem>> map : routeTabel1x) {
for(List<RouteItem>v:map.values()) { // 使用 compute 直接替换
Collections.sort(v); map.replaceAll((key, oldList) -> {
if (oldList == null || oldList.isEmpty()) {
return oldList;
} }
List<RouteItem> newList = new ArrayList<>(oldList);
Collections.sort(newList);
return newList;
});
} }
// System.out.println(routeTabel1x);
routeTabel1 = routeTabel1x; // 更新索引路由表
} }
// 更新路由表 // 更新路由表
public void updateRouteTabel() { public void updateRouteTabel() {
@@ -255,7 +231,7 @@ public class SRv6Router {
nlink.setSRv6Router(this); nlink.setSRv6Router(this);
nlink.addIPv6LinkStateListener(listener); // 添加链路状态监听器 nlink.addIPv6LinkStateListener(listener); // 添加链路状态监听器
nlink.setReceiveConsumer(srhReceive); // 设置接收处理器 nlink.setReceiveConsumer(receiveConsumer); // 设置接收处理器
if (nlink instanceof ControlledIPv6NetworkLink) { if (nlink instanceof ControlledIPv6NetworkLink) {
((ControlledIPv6NetworkLink) nlink).setRerouteConsumer(defaultReroute); // 设置重路由处理器 ((ControlledIPv6NetworkLink) nlink).setRerouteConsumer(defaultReroute); // 设置重路由处理器
((ControlledIPv6NetworkLink) nlink).setCongressCondition(congressLock, congressCondition); // 设置拥塞条件 ((ControlledIPv6NetworkLink) nlink).setCongressCondition(congressLock, congressCondition); // 设置拥塞条件
@@ -273,7 +249,7 @@ public class SRv6Router {
ArrayList<Map<IPv6Address, List<RouteItem>>> routeTabel1x = new ArrayList<Map<IPv6Address, List<RouteItem>>>( ArrayList<Map<IPv6Address, List<RouteItem>>> routeTabel1x = new ArrayList<Map<IPv6Address, List<RouteItem>>>(
IPv6_BITS + 1); IPv6_BITS + 1);
for (int i = 0; i < IPv6_BITS + 1; i++) { for (int i = 0; i < IPv6_BITS + 1; i++) {
routeTabel1x.add(new HashMap<IPv6Address, List<RouteItem>>(1024, 0.5f)); routeTabel1x.add(new ConcurrentHashMap<IPv6Address, List<RouteItem>>());
} }
// 按前缀长度组织路由表 // 按前缀长度组织路由表
@@ -323,9 +299,9 @@ public class SRv6Router {
} }
// 插入SRH并路由数据包 // 插入SRH并路由数据包
public void insertSRHandRoutePacket(IPv6NetworkLink link, IPv6Packet ipp) { public void insertHeaderAndRoutePacket(IPv6NetworkLink link, IPv6Packet ipp) {
insertHopByHopHeader(ipp); insertHopByHopHeader(ipp);//插入逐跳头
insertSRHeader(ipp); // 插入段路由头 //insertSRHeader(ipp); // 插入段路由头
routePacket(link, ipp); // 路由数据包 routePacket(link, ipp); // 路由数据包
} }
@@ -384,16 +360,13 @@ public class SRv6Router {
} }
private void routePacket(IPv6Packet iPv6Packet) { private void routePacket(IPv6Packet iPv6Packet) {
routePacket(null, iPv6Packet, false); routePacket(null, iPv6Packet);
} }
// 路由数据包(默认非重路由)
private void routePacket(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet) {
routePacket(linkfrom, iPv6Packet, false);
}
// 路由数据包主方法 // 路由数据包主方法
private void routePacket(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, boolean reroute) { private void routePacket(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet) {
StringBuilder dbg = null; StringBuilder dbg = null;
if (debug) { if (debug) {
dbg = new StringBuilder(); // 调试信息 dbg = new StringBuilder(); // 调试信息
@@ -406,7 +379,7 @@ public class SRv6Router {
List<RouteItem> searchResult = getTabelByAddress(dest); List<RouteItem> searchResult = getTabelByAddress(dest);
if (searchResult!=null&&(!searchResult.isEmpty())) { if (searchResult!=null&&(!searchResult.isEmpty())) {
// 匹配到路由表,执行负载均衡路由 // 匹配到路由表,执行负载均衡路由
routingLoadBalance(linkfrom, iPv6Packet, reroute, dbg, searchResult); routingLoadBalance(linkfrom, iPv6Packet, dbg, searchResult);
return; return;
} }
@@ -441,7 +414,7 @@ public class SRv6Router {
// 重新搜索路由表 // 重新搜索路由表
List<RouteItem> searchResult2 = getTabelByAddress(dest); List<RouteItem> searchResult2 = getTabelByAddress(dest);
if (searchResult2!=null&&(!searchResult2.isEmpty())) { if (searchResult2!=null&&(!searchResult2.isEmpty())) {
routingLoadBalance(linkfrom, iPv6Packet, reroute, dbg, searchResult2); routingLoadBalance(linkfrom, iPv6Packet, dbg, searchResult2);
return; return;
} }
@@ -508,8 +481,8 @@ public class SRv6Router {
private Condition congressCondition = congressLock.newCondition(); // 拥塞条件 private Condition congressCondition = congressLock.newCondition(); // 拥塞条件
// 负载均衡路由 // 负载均衡路由
private boolean routingLoadBalance(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, boolean reroute, private boolean routingLoadBalance(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet,
StringBuilder dbg, List<RouteItem> routes) throws IllegalRawDataException, IOException { StringBuilder dbg, List<RouteItem> routes) throws IOException {
if(routes==null||routes.isEmpty()) { if(routes==null||routes.isEmpty()) {
//System.out.println("Route not found:" + iPv6Packet); //System.out.println("Route not found:" + iPv6Packet);
@@ -517,7 +490,7 @@ public class SRv6Router {
} }
for (double i = 1; i < 100; i += 0.1) { for (double i = 1; i < 100; i += 0.1) {
if (loadBalance(linkfrom, iPv6Packet, reroute, dbg, routes, i)) { if (loadBalance(linkfrom, iPv6Packet, dbg, routes, i)) {
return true; return true;
} }
@@ -536,9 +509,9 @@ public class SRv6Router {
return false; // 路由失败 return false; // 路由失败
} }
private boolean loadBalance(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, boolean reroute, StringBuilder dbg, private boolean loadBalance(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, StringBuilder dbg,
List<RouteItem> routes, double cscale) List<RouteItem> routes, double cscale)
throws IllegalRawDataException, IOException { throws IOException {
// 遍历可用路由进行负载均衡 // 遍历可用路由进行负载均衡
for (RouteItem tri : routes) { for (RouteItem tri : routes) {
IPv6NetworkLink link = tri.getDestlink(); IPv6NetworkLink link = tri.getDestlink();
@@ -564,52 +537,63 @@ public class SRv6Router {
dbg.append("matched.\n"); dbg.append("matched.\n");
} }
// 找到可用链路,处理数据包 // 找到可用链路,处理数据包
processPacket(linkfrom, iPv6Packet, tri, reroute); processPacket(linkfrom, iPv6Packet, tri);
return true; return true;
} }
return false; return false;
} }
// 处理数据包转发 // 处理数据包转发
private void processPacket(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, RouteItem ri, boolean reroute) private void processPacket(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, RouteItem ri)
throws IllegalRawDataException, IOException { throws IOException {
int hop = iPv6Packet.getHopLimit(); int hop = iPv6Packet.getHopLimit();
if (ri.getDestlink().isLoopBack()) { // 环回链路处理 if (ri.getDestlink().isLoopBack()) { // 环回链路处理
IPv6HopByHopHeader iPv6HopByHopHeader=iPv6Packet.getHopByHopHeader();
if(iPv6Packet.getRouteCounter().get()<=0) {
if (iPv6HopByHopHeader != null&&linkfrom instanceof KLALBRemoteLink) {
processKLALBOAM(iPv6Packet, linkfrom.getAddressGroups().get(0).getAddress(),
((KLALBRemoteLink) linkfrom).getRemoteVaddr().getAddress(), iPv6HopByHopHeader);
}
}
IPv6SegmentRoutingHeader srhh = iPv6Packet.getSegmentRoutingHeader(); IPv6SegmentRoutingHeader srhh = iPv6Packet.getSegmentRoutingHeader();
if (srhh != null) { if (srhh != null) {
processSRv6Packet(linkfrom, iPv6Packet, ri, srhh, iPv6Packet.getHopByHopHeader(), reroute); // SRv6特殊处理 processSRv6Packet(linkfrom, iPv6Packet, ri, srhh); // SRv6特殊处理
} else { } else {
sendPacketToRouteItem(iPv6Packet, ri); sendPacketToRouteItem(linkfrom,iPv6Packet, ri);
} }
} else { // 普通链路处理 } else { // 普通链路处理
if(ri.getDestlink().isFilter()){
}else {
// 检查重路由计数 // 检查重路由计数
if (iPv6Packet.getRerouteCounter().getAndIncrement() >= MAX_REROUTE_COUNT) { int count = iPv6Packet.getRouteCounter().getAndIncrement();
if (count > MAX_REROUTE_COUNT) {
return; // 超过最大重路由次数,丢弃 return; // 超过最大重路由次数,丢弃
} }
if (!reroute) { if (count <= 0) {
hop--; // 减少TTL(非重路由时) hop--; // 减少TTL(非重路由时)
} }
}
if (hop > 0) { // TTL有效 if (hop > 0) { // TTL有效
iPv6Packet.setHopLimit(hop); // 更新TTL iPv6Packet.setHopLimit(hop); // 更新TTL
sendPacketToRouteItem(iPv6Packet, ri); // 发送数据包 sendPacketToRouteItem(linkfrom,iPv6Packet, ri); // 发送数据包
} else { } else {
sendTTLExceedPacket(iPv6Packet); // TTL超时 sendTTLExceedPacket(iPv6Packet); // TTL超时
} }
} }
} }
private void sendPacketToRouteItem(IPv6Packet iPv6Packet, RouteItem ri) throws IOException { private void sendPacketToRouteItem(IPv6NetworkLink linkfrom,IPv6Packet iPv6Packet, RouteItem ri) throws IOException {
if (iPv6Packet.getPayload() instanceof ICMPv6PostcardPacket && ri.getDestlink().isLoopBack()) { if (iPv6Packet.getPayload() instanceof ICMPv6PostcardPacket && ri.getDestlink().isLoopBack()) {
onPostcardReceive(iPv6Packet); onPostcardReceive(linkfrom,iPv6Packet);
} else { } else {
ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop()); ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop());
} }
} }
private void onPostcardReceive(IPv6Packet postcards) { private void onPostcardReceive(IPv6NetworkLink linkfrom,IPv6Packet postcards) {
ICMPv6PostcardPacket postcardsi = (ICMPv6PostcardPacket) postcards.getPayload(); ICMPv6PostcardPacket postcardsi = (ICMPv6PostcardPacket) postcards.getPayload();
for (PostcardEntry postcard : postcardsi.getPostcards()) { for (PostcardEntry postcard : postcardsi.getPostcards()) {
IPv6Address sid = postcard.getSID(); IPv6Address sid = postcard.getSID();
@@ -620,7 +604,7 @@ public class SRv6Router {
if (ri.getNexthop().equals(sid)) { if (ri.getNexthop().equals(sid)) {
if (ri.getDestlink() instanceof KLALBRemoteLink) { if (ri.getDestlink() instanceof KLALBRemoteLink) {
KLALBRemoteLink rem = (KLALBRemoteLink) ri.getDestlink(); KLALBRemoteLink rem = (KLALBRemoteLink) ri.getDestlink();
rem.onPostcardReceive(postcard); rem.onPostcardReceive(linkfrom,postcard);
} }
} }
} }
@@ -630,7 +614,7 @@ public class SRv6Router {
} }
// 发送ICMP TTL超时消息 // 发送ICMP TTL超时消息
private void sendTTLExceedPacket(IPv6Packet iPv6Packet) throws IOException, IllegalRawDataException { private void sendTTLExceedPacket(IPv6Packet iPv6Packet) throws IOException {
enqueuePacketSendTask(() -> { enqueuePacketSendTask(() -> {
// 构建IPv6数据包封装ICMP消息 // 构建IPv6数据包封装ICMP消息
IPv6Packet icmpv = new IPv6Packet(); IPv6Packet icmpv = new IPv6Packet();
@@ -651,34 +635,16 @@ public class SRv6Router {
// 处理SRv6数据包 // 处理SRv6数据包
private void processSRv6Packet(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, RouteItem ri, private void processSRv6Packet(IPv6NetworkLink linkfrom, IPv6Packet iPv6Packet, RouteItem ri,
IPv6SegmentRoutingHeader srhh, IPv6HopByHopHeader iPv6HopByHopHeader, boolean reroute) IPv6SegmentRoutingHeader srhh)
throws IllegalRawDataException, IOException { throws IOException {
if (srhh.getSegmentsLeft() <= 0) { // 所有段已处理完毕 if (srhh.getSegmentsLeft() <= 0) { // 所有段已处理完毕
if (iPv6HopByHopHeader != null) { sendPacketToRouteItem(linkfrom,iPv6Packet, ri);
int sl = srhh.getSegmentsLeft();
// IPv6Address prevSID
// =sl+1>=srhh.getAddresses().size()?iPv6Packet.getSourceAddress():srhh.getAddresses().get(sl+1);
if (linkfrom instanceof KLALBRemoteLink) {
processKLALBOAM(iPv6Packet, linkfrom.getAddressGroups().get(0).getAddress(),
((KLALBRemoteLink) linkfrom).getRemoteVaddr().getAddress(), iPv6HopByHopHeader);
}
}
// System.out.println(iPv6HopByHopHeader);
sendPacketToRouteItem(iPv6Packet, ri);
} else {
if (reroute) {
// 重路由处理
} else { } else {
if (iPv6Packet.getRouteCounter().get()<=0) {
// 重路由不处理
int oldSL = srhh.getSegmentsLeft(); int oldSL = srhh.getSegmentsLeft();
if (iPv6HopByHopHeader != null) {
// IPv6Address prevSID
// =oldSL+1>=srhh.getAddresses().size()?iPv6Packet.getSourceAddress():srhh.getAddresses().get(oldSL+1);
if (linkfrom instanceof KLALBRemoteLink) {
processKLALBOAM(iPv6Packet, linkfrom.getAddressGroups().get(0).getAddress(),
((KLALBRemoteLink) linkfrom).getRemoteVaddr().getAddress(), iPv6HopByHopHeader);
}
}
// 正常SRv6处理:移动到下一个段 // 正常SRv6处理:移动到下一个段
int newSL = oldSL - 1; int newSL = oldSL - 1;
srhh.setSegmentsLeft(newSL); // 更新剩余段数 srhh.setSegmentsLeft(newSL); // 更新剩余段数
@@ -687,7 +653,7 @@ public class SRv6Router {
// 记录热点地址(用于流量工程) // 记录热点地址(用于流量工程)
if (iPv6Packet.getPayload().getProtocolNumber() != KLALBRoutingProtocol.DEFAULT_PROTOCOL_NUMBER) if (iPv6Packet.getPayload().getProtocolNumber() != KLALBRoutingProtocol.DEFAULT_PROTOCOL_NUMBER)
klalbRouteProtol.putHotspotAddress(iPv6Packet.getSourceAddress()); klalbRouteProtol.putHotspotAddress(iPv6Packet.getSourceAddress());
routePacket(linkfrom, iPv6Packet, reroute); // 继续路由 routePacket(linkfrom, iPv6Packet); // 继续路由
} }
} }
@@ -814,7 +780,7 @@ public class SRv6Router {
if(ecn) { if(ecn) {
packet.markCE(); packet.markCE();
} }
insertSRHandRoutePacket(null, packet); // 插入SRH并路由 insertHeaderAndRoutePacket(null, packet); // 插入SRH并路由
long time=System.nanoTime()-start; long time=System.nanoTime()-start;
backplaneCount(time,ecn); backplaneCount(time,ecn);
} catch (Exception e) { } catch (Exception e) {
@@ -827,7 +793,7 @@ public class SRv6Router {
public void onReceive(IPv6NetworkLink link,IPv6Packet t){ public void onReceive(IPv6NetworkLink link,IPv6Packet t){
if (unduplicate(t)) { if (unduplicate(t)) {
insertSRHandRoutePacket(link, t); // 插入SRH并路由数据包 insertHeaderAndRoutePacket(link, t); // 插入SRH并路由数据包
} }
} }
@@ -873,7 +839,6 @@ public class SRv6Router {
private volatile long backplanePPSMax=0; private volatile long backplanePPSMax=0;
private volatile long prevTime=System.nanoTime(); private volatile long prevTime=System.nanoTime();
private Timer backplaneTimer=new Timer();
private void updateBackplaneCounter() { private void updateBackplaneCounter() {
long curr=System.nanoTime(); long curr=System.nanoTime();
long totalTime=timeAdder.getAndReset(); long totalTime=timeAdder.getAndReset();
@@ -916,22 +881,24 @@ public class SRv6Router {
} }
// 构造函数 // 构造函数
public SRv6Router(IPv6AddressGroup hostAddress, HighAccuracyClock clock) { public SRv6Router(IPv6AddressGroup endSID,IPv6AddressGroup networkGroup, HighAccuracyClock clock) {
super(); super();
this.locator = hostAddress; this.locator = endSID;
this.clock = clock; this.clock = clock;
// initWorkerThreads(); // initWorkerThreads();
// 创建环回链路 // 创建环回链路
this.inLoopBack = new LoopbackIPv6NetworkLink( this.inLoopBack = new LoopbackIPv6NetworkLink(
List.of(new IPv6AddressGroup(IPv6Address.LOOPBACK, 128), hostAddress), this); List.of(new IPv6AddressGroup(IPv6Address.LOOPBACK, 128), endSID), this);
linkTabel.add(inLoopBack); // 添加到链路表 linkTabel.add(inLoopBack); // 添加到链路表
backplaneTimer.scheduleAtFixedRate(new TimerTask() { this.srhInserter=new SRHInsertNetworkLink(this,networkGroup);
linkTabel.add(srhInserter);
KLALBScheduler.getScheduler().scheduleWithFixedDelay(new Runnable() {
@Override @Override
public void run() { public void run() {
updateBackplaneCounter(); updateBackplaneCounter();
} }
}, 100, 100); }, 100, 100, TimeUnit.MILLISECONDS);
} }
/* /*
@@ -1,114 +0,0 @@
package org.kne.concurrent;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.EventTranslator;
import com.lmax.disruptor.LiteBlockingWaitStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.Sequence;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.SleepingWaitStrategy;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
public class DisruptorExecutor implements Executor{
public static final DisruptorExecutor defaultExecutor=new DisruptorExecutor();
private RunnableHandler[]rh;
public DisruptorExecutor() {
this(Runtime.getRuntime().availableProcessors(),1024);
}
public DisruptorExecutor(int threadcount,int bufferSize) {
this(threadcount,bufferSize,Executors.defaultThreadFactory());
//this(threadcount,bufferSize,Thread.ofVirtual().factory());
}
public DisruptorExecutor(int threadcount,int bufferSize,ThreadFactory th) {
rh=new RunnableHandler[threadcount];
for (int i = 0; i < rh.length; i++) {
rh[i]=new RunnableHandler(bufferSize,th);
}
}
private class RunnableHandler implements EventHandler<AtomicReference<Runnable>>{
private Disruptor<AtomicReference<Runnable>>ring;
public RunnableHandler(int bufferSize,ThreadFactory tf)
{ring=new Disruptor<AtomicReference<Runnable>>(new EventFactory<AtomicReference<Runnable>>() {
@Override
public AtomicReference<Runnable> newInstance() {
return new AtomicReference<Runnable>();
}
}, bufferSize,tf,ProducerType.MULTI, new SleepingWaitStrategy());
ring.handleEventsWith(this);
ring.start();
}
@Override
public void onEvent(AtomicReference<Runnable> arg0, long sequence, boolean onEndOfBatch) throws Exception {
//System.out.println(sequence);
Runnable r =arg0.get();
if(r!=null)
try {
r.run();
}catch(Throwable th) {
th.printStackTrace();
}
}
}
/*
* public final class MyHandler implements EventHandler<ValueEvent>
{
public void onEvent(final ValueEvent entry, final long sequence, final boolean onEndOfBatch)
{
if ((sequence % numberOfConsumers) == ordinal)
{
// Process the event
}
}
}
*/
private AtomicLong al=new AtomicLong();
@Override
public void execute(Runnable command) {
int v=(int) (al.getAndIncrement()%rh.length);
rh[v].ring.publishEvent(new EventTranslator<AtomicReference<Runnable>>() {
@Override
public void translateTo(AtomicReference<Runnable> arg0, long arg1) {
arg0.set(command);
//arg0.compareAndSet(null, command);
}
});
}
public static void main(String[] args) throws InterruptedException {
DisruptorExecutor dre=new DisruptorExecutor();
for (int i = 0; i < 20; i++) {
dre.execute(()->{
System.out.println("run");
});
System.out.println("exc");
}
Thread.sleep(1000);
}
}