forked from KNEMC/KLALB
KLALB 3.6.0开发一半的状态
This commit is contained in:
@@ -0,0 +1,987 @@
|
||||
package org.kne.cloud.network.klalb;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jctools.queues.MpscArrayQueue;
|
||||
import org.kne.cloud.clock.HighAccuracyClock;
|
||||
import org.kne.cloud.clock.NTPTimestamps;
|
||||
import org.kne.cloud.clock.ReliabilityBackoffTimeClock;
|
||||
import org.kne.cloud.clock.WatchDogTimer;
|
||||
import org.kne.cloud.network.MultipurposeSocketAddress;
|
||||
import org.kne.cloud.network.ThreadTool;
|
||||
import org.kne.cloud.network.congestion.BBRCongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.CongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.CongestionAlgorithms;
|
||||
import org.kne.cloud.network.congestion.DetnetCongestionAlgorithm;
|
||||
import org.kne.cloud.network.congestion.SendPacketSlidingWindow;
|
||||
import org.kne.cloud.network.ipv6.ControlledIPv6NetworkLink;
|
||||
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.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.DelayMonitorData;
|
||||
import org.kne.cloud.network.monitor.LinkStatus;
|
||||
import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||
import org.kne.cloud.network.perf.TESTNPacket;
|
||||
import org.kne.cloud.network.te.BandwidthDistributer;
|
||||
import org.kne.concurrent.SpinLock;
|
||||
import org.kne.concurrent.ThreadParker;
|
||||
import org.kne.math.Long128;
|
||||
|
||||
public class KLALBRemoteLink extends AbstractControlledIPv6NetworkLink implements ControlledIPv6NetworkLink {
|
||||
|
||||
private static final int HEADER_CALIBRATE = 40;
|
||||
|
||||
private static final boolean debug = false;
|
||||
|
||||
private static final boolean showpacket = false;
|
||||
|
||||
private volatile boolean closed = false;
|
||||
|
||||
private volatile KLALBController klalbController;
|
||||
|
||||
public KLALBController getKlalbController() {
|
||||
return klalbController;
|
||||
}
|
||||
|
||||
|
||||
private volatile IPv6AddressGroup remoteVaddr;
|
||||
|
||||
public IPv6AddressGroup getRemoteVaddr() {
|
||||
return remoteVaddr;
|
||||
}
|
||||
|
||||
private HighAccuracyClock sysclk ;
|
||||
|
||||
public void waitForRemoteVaddrAvaliable(long timeout) throws SocketTimeoutException {
|
||||
long s = System.nanoTime();
|
||||
while (remoteVaddr == null) {
|
||||
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (System.nanoTime() - s > timeout * 1000000)
|
||||
throw new SocketTimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
public SpeedAndTrafficAndDelayMonitorDataImpl getMonitor() {
|
||||
return monitor;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return remoteVaddr + "\t" +name+"\n" +status+"\t"+monitor.toString();
|
||||
}
|
||||
|
||||
private String name;
|
||||
private LinkStatus status=new LinkStatus();
|
||||
private SpeedAndTrafficAndDelayMonitorDataImpl monitor;
|
||||
private volatile KLALBPacketLink kplink;
|
||||
private MultipurposeSocketAddress bindAddress;
|
||||
private MultipurposeSocketAddress socketAddress;
|
||||
|
||||
|
||||
public void setKplink(KLALBPacketLink kplink) {
|
||||
this.kplink = kplink;
|
||||
}
|
||||
|
||||
public KLALBPacketLink getKplink() {
|
||||
return kplink;
|
||||
}
|
||||
|
||||
public MultipurposeSocketAddress getSocketAddress() {
|
||||
return socketAddress;
|
||||
}
|
||||
|
||||
public MultipurposeSocketAddress getBindAddress() {
|
||||
return bindAddress;
|
||||
}
|
||||
|
||||
private IPv6AddressGroup addressGroup;
|
||||
private IPv6AddressGroup peerAddress;
|
||||
|
||||
@Override
|
||||
public List<IPv6AddressGroup> getAddressGroups() {
|
||||
List<IPv6AddressGroup> list = new ArrayList<>();
|
||||
list.add(addressGroup);
|
||||
return list;
|
||||
}
|
||||
|
||||
public IPv6AddressGroup getPeerAddress() {
|
||||
return peerAddress;
|
||||
}
|
||||
|
||||
public KLALBRemoteLink(KLALBController controller, MultipurposeSocketAddress mpa, IPv6AddressGroup address) {
|
||||
this(controller,mpa, null,address);
|
||||
}
|
||||
|
||||
public KLALBRemoteLink(KLALBController controller,KLALBPacketLink kpl, IPv6AddressGroup address) {
|
||||
this.klalbController=controller;
|
||||
sysclk = klalbController.getClock();
|
||||
this.kplink = kpl;
|
||||
this.addressGroup = address;
|
||||
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||
name=kpl.toString();
|
||||
}
|
||||
|
||||
private KLALBRemoteLink(KLALBController controller,MultipurposeSocketAddress mpa, MultipurposeSocketAddress bindaddr, IPv6AddressGroup address) {
|
||||
this.klalbController=controller;
|
||||
sysclk = klalbController.getClock();
|
||||
this.socketAddress = mpa;
|
||||
this.bindAddress = bindaddr;
|
||||
this.addressGroup = address;
|
||||
monitor=new SpeedAndTrafficAndDelayMonitorDataImpl(sysclk);
|
||||
if (bindaddr == null) {
|
||||
name="→" + mpa.toString();
|
||||
} else {
|
||||
name=bindaddr.toString() + "→" + mpa.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public KLALBRemoteLink(KLALBController controller,MultipurposeSocketAddress mpa, MultipurposeSocketAddress bind) {
|
||||
this(controller,mpa, bind, null);
|
||||
}
|
||||
|
||||
public KLALBRemoteLink(KLALBController controller,MultipurposeSocketAddress mpa) {
|
||||
this(controller,mpa, (IPv6AddressGroup) null);
|
||||
}
|
||||
|
||||
public KLALBRemoteLink(KLALBController controller,KLALBPacketLink link) {
|
||||
this(controller,link, (IPv6AddressGroup) null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private CongestionAlgorithm algorithm;
|
||||
|
||||
private SendPacketSlidingWindow<UUID, IPv6Packet> sendWindow;
|
||||
|
||||
|
||||
|
||||
private class RemoteSender implements Runnable {
|
||||
|
||||
private MpscArrayQueue<KLALBPacket> sendQueue = new MpscArrayQueue<KLALBPacket>(8192);
|
||||
private WatchDogTimer watchdog = new WatchDogTimer(400000000L);
|
||||
|
||||
private ThreadParker tlock = new ThreadParker();
|
||||
|
||||
private volatile long time = System.nanoTime();
|
||||
private volatile long pingInterval = 100000000L;
|
||||
|
||||
private Lock sendLock=new SpinLock();
|
||||
|
||||
private boolean checkPingTime() {
|
||||
long cu = System.nanoTime();
|
||||
if (cu - time > pingInterval) {
|
||||
time = cu;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Queue<KLALBPacket> getSendQueue() {
|
||||
return sendQueue;
|
||||
}
|
||||
|
||||
|
||||
public WatchDogTimer getWatchdog() {
|
||||
return watchdog;
|
||||
}
|
||||
|
||||
public long getPingInterval() {
|
||||
return pingInterval;
|
||||
}
|
||||
public void setPingInterval(long pingInterval) {
|
||||
this.pingInterval = pingInterval;
|
||||
}
|
||||
|
||||
private volatile long flushInterval=1000000L;
|
||||
|
||||
public long getFlushInterval() {
|
||||
return flushInterval;
|
||||
}
|
||||
public void setFlushInterval(long flushInterval) {
|
||||
this.flushInterval = flushInterval;
|
||||
}
|
||||
private long flushTime=System.nanoTime();
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
writeKLALBPacketToKPL(new ADDRREQPacket());
|
||||
writeKLALBPacketToKPL(new ADDRREQPacket());
|
||||
if (addressGroup != null) {
|
||||
writeKLALBPacketToKPL(new ADDRPacket(addressGroup));
|
||||
writeKLALBPacketToKPL(new ADDRPacket(addressGroup));
|
||||
}
|
||||
writeKLALBPacketToKPL(new VADDRREQPacket());
|
||||
writeKLALBPacketToKPL(new VADDRREQPacket());
|
||||
writeKLALBPacketToKPL(new VADDRPacket(klalbController.getSelf()));
|
||||
writeKLALBPacketToKPL(new VADDRPacket(klalbController.getSelf()));
|
||||
kplink.flush();
|
||||
while ((!kplink.isClosed()) && (!closed)) {
|
||||
if (checkPingTime()) {
|
||||
ping();
|
||||
if (remoteVaddr == null)
|
||||
sendPacket(new VADDRREQPacket());
|
||||
if (peerAddress == null)
|
||||
sendPacket(new ADDRREQPacket());
|
||||
|
||||
}/*sendLock.lock();
|
||||
int n;
|
||||
try {
|
||||
n = sendQueue.drain((tkpp)->{
|
||||
|
||||
try {
|
||||
kplink.writeKLALBPacket(tkpp);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
},100);
|
||||
}finally {
|
||||
sendLock.unlock();
|
||||
}
|
||||
if (n>0) {
|
||||
watchdog.feed();
|
||||
} else {
|
||||
tlock.parkNanos(1000000L);
|
||||
}*/
|
||||
long curr=System.nanoTime();
|
||||
if(curr-flushTime>=flushInterval) {
|
||||
flushTime=curr;
|
||||
sendLock.lock();
|
||||
try {
|
||||
kplink.flush();
|
||||
watchdog.feed();
|
||||
}finally {
|
||||
sendLock.unlock();
|
||||
}
|
||||
}
|
||||
tlock.parkNanos(1000000L);
|
||||
|
||||
}
|
||||
} catch (StreamCorruptedException sce) {
|
||||
sce.printStackTrace();
|
||||
} catch (IOException | UnresolvedAddressException e) {
|
||||
if (debug)
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
kplink.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tpk.unpark();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean send(KLALBPacket blk) {
|
||||
boolean b=sendQueue.add(blk);
|
||||
if(b) {
|
||||
tlock.unpark();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
public void sendDirect(KLALBPacket blk) {
|
||||
sendLock.lock();
|
||||
try {
|
||||
writeKLALBPacketToKPL(blk);
|
||||
} catch (IOException | UnresolvedAddressException e) {
|
||||
if (debug)
|
||||
e.printStackTrace();
|
||||
try {
|
||||
kplink.close();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
tpk.unpark();
|
||||
}finally {
|
||||
sendLock.unlock();
|
||||
}
|
||||
watchdog.feed();
|
||||
tlock.unpark();
|
||||
}
|
||||
|
||||
|
||||
public long getQueueUsed() {
|
||||
long used=0;
|
||||
for(KLALBPacket pack:sendQueue) {
|
||||
used+=pack.getTotalLength();
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class RemoteReceiver implements Runnable {
|
||||
|
||||
private WatchDogTimer watchdog = new WatchDogTimer(400000000L);
|
||||
private long rtt=Long.MAX_VALUE/1024;
|
||||
private long rttMin=Long.MAX_VALUE/1024;
|
||||
AtomicBoolean fst = new AtomicBoolean(true);
|
||||
//ReentrantLock readLock = new ReentrantLock();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while ((!kplink.isClosed()) && (!closed)) {
|
||||
KLALBPacket kppb = readKLALBPacketFromKPL();
|
||||
|
||||
if (kppb == null) {
|
||||
break;
|
||||
}
|
||||
watchdog.feed();
|
||||
KLALBPacket kpp = kppb;
|
||||
//SRv6Router.getDefaultExecutor().execute(() -> {
|
||||
debugShowPacket("RX", kpp);
|
||||
UUID val = null;
|
||||
long delay = Long.MAX_VALUE / 1024;
|
||||
switch (kpp.getType()) {
|
||||
case KLALBPacket.PING:
|
||||
long pct = System.nanoTime() - kpp.getRcvtime();
|
||||
Long128 curr = sysclk.getCurrentTimeNanos();
|
||||
Long128 rcv = curr.subtract(pct);
|
||||
|
||||
Long128 local1281 = NTPTimestamps.nanosToNtp128BitTimestamp(curr);
|
||||
PONGPacket pong = new PONGPacket(((PINGPacket) kpp).getTime(),
|
||||
NTPTimestamps.ntp128To64(NTPTimestamps.nanosToNtp128BitTimestamp(rcv)).longValue(),
|
||||
NTPTimestamps.ntp128To64(NTPTimestamps.nanosToNtp128BitTimestamp(curr)).longValue(),
|
||||
monitor.getUploadBandwidth().calculateBandwidth(500000000L),
|
||||
monitor.getDownloadBandwidth().calculateBandwidth(500000000L));
|
||||
sendPacket(pong);
|
||||
/*
|
||||
* long prcv1=pong.getTimepingrcv();
|
||||
* System.out.println("prcv"+NTPTimestamps.nanosSince1970ToString(
|
||||
* NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
* prcv1,local1281)))); long posnd1=pong.getTimepongsnd();
|
||||
* System.out.println("posnd"+NTPTimestamps.nanosSince1970ToString(
|
||||
* NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
* posnd1,local1281))));
|
||||
*/
|
||||
break;
|
||||
case KLALBPacket.PONG:
|
||||
PONGPacket png = (PONGPacket) kpp;
|
||||
/*
|
||||
* long ul = png.getRcvtime() - png.getTimepingsnd() - (png.getTimepongsnd() -
|
||||
* png.getTimepingrcv());
|
||||
*/
|
||||
Long128 local = sysclk.getCurrentTimeNanos();
|
||||
Long128 local128 = NTPTimestamps.nanosToNtp128BitTimestamp(local);
|
||||
|
||||
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(png.getTimepingsnd(), local128));
|
||||
// System.out.println("psnd"+NTPTimestamps.nanosSince1970ToString(
|
||||
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
// psnd,local128))));
|
||||
Long128 prcv = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(png.getTimepingrcv(), local128));
|
||||
// System.out.println("prcv"+NTPTimestamps.nanosSince1970ToString(
|
||||
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
// prcv,local128))));
|
||||
Long128 posnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(png.getTimepongsnd(), local128));
|
||||
// System.out.println("posnd"+NTPTimestamps.nanosSince1970ToString(
|
||||
// NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
// posnd,local128))));
|
||||
|
||||
long DsndDelay = prcv.subtract(psnd).longValue();
|
||||
long DrcvDelay = local.subtract(posnd).longValue();
|
||||
// System.out.println(DsndDelay+" "+DrcvDelay);
|
||||
|
||||
rtt = DsndDelay + DrcvDelay;
|
||||
if(rtt<rttMin) {
|
||||
rttMin=rtt;
|
||||
}else {
|
||||
rttMin=(rttMin*99+rtt)/100;
|
||||
}
|
||||
if (DsndDelay >= 0 && DrcvDelay >= 0) {
|
||||
delay = DrcvDelay;
|
||||
monitor.recordUploadDelay(DsndDelay);
|
||||
//sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.001);
|
||||
} else {
|
||||
long Dfallback = rtt / 2;
|
||||
if (Dfallback >= 0) {
|
||||
delay = Dfallback;
|
||||
monitor.recordUploadDelay(Dfallback);
|
||||
}
|
||||
sysclk.adjustClock(Long128.valueOf( DsndDelay-DrcvDelay), 0.1);
|
||||
}
|
||||
|
||||
algorithm.setCurrentBandwidth(png.getDownSpeed());
|
||||
break;
|
||||
case KLALBPacket.BWINF:
|
||||
BWINFPacket bwi = (BWINFPacket) kpp;
|
||||
algorithm.setCurrentBandwidth(bwi.getDownSpeed());
|
||||
break;
|
||||
case KLALBPacket.ADDRREQ:
|
||||
if (addressGroup != null)
|
||||
sendPacket(new ADDRPacket(addressGroup));
|
||||
break;
|
||||
case KLALBPacket.ADDR:
|
||||
peerAddress = ((ADDRPacket) kpp).getAddr();
|
||||
if (addressGroup == null) {
|
||||
byte[] ab = peerAddress.getAddress().toByteArray();
|
||||
ab[15] = 2;
|
||||
IPv6AddressGroup ardg2 = new IPv6AddressGroup(IPv6Address.valueOf(ab),
|
||||
peerAddress.getPrefixLength());
|
||||
if (ardg2 != null)
|
||||
addressGroup = ardg2;
|
||||
}
|
||||
KLALBRemoteLink.this.onAddressUpdate();
|
||||
|
||||
break;
|
||||
case KLALBPacket.VADDRREQ:
|
||||
sendPacket(new VADDRPacket(klalbController.getSelf()));
|
||||
break;
|
||||
case KLALBPacket.VADDR:
|
||||
IPv6AddressGroup vdr = ((VADDRPacket) kpp).getVaddr();
|
||||
|
||||
remoteVaddr = vdr;
|
||||
sendPacket(new VADDRACKPacket());
|
||||
if (fst.compareAndSet(true, false)) {
|
||||
// coll.resetCoolingTime();
|
||||
status.setState(LinkStatus.UP);
|
||||
KLALBRemoteLink.this.onOnlineStateUpdate();
|
||||
}
|
||||
KLALBRemoteLink.this.onLocatorUpdate();
|
||||
|
||||
break;
|
||||
case KLALBPacket.VADDRACK:
|
||||
break;
|
||||
case KLALBPacket.TESTN:
|
||||
break;
|
||||
case KLALBPacket.IPV6OVERKLALB:
|
||||
|
||||
IPv6OverKLALBPacket ivk = (IPv6OverKLALBPacket) kpp;
|
||||
IPv6Packet iv6 = ivk.getIPv6Packet();
|
||||
if (getSrv6Router() != null) {
|
||||
getSrv6Router().onReceive(KLALBRemoteLink.this, iv6);
|
||||
}
|
||||
|
||||
KLALBOAMHopByHopTLV ktlv = null;
|
||||
|
||||
long btimes = 0;
|
||||
IPv6HopByHopHeader hop = iv6.getHopByHopHeader();
|
||||
if (hop != null) {
|
||||
List<Long> ptlv = new ArrayList<>();
|
||||
List<IPv6HopByHopTLV> tlvs = hop.getTlvs();
|
||||
for (IPv6HopByHopTLV tlv : tlvs) {
|
||||
if (tlv instanceof KLALBOAMHopByHopTLV) {
|
||||
ktlv = (KLALBOAMHopByHopTLV) tlv;
|
||||
val = ktlv.getUUID();
|
||||
btimes = ktlv.getTimestamp();
|
||||
ptlv.add(btimes);
|
||||
} else if (tlv instanceof KLALBPassportHopByHopTLV) {
|
||||
ptlv.add(btimes + ((KLALBPassportHopByHopTLV) tlv).getTimestampOffsetLong());
|
||||
}
|
||||
}
|
||||
if (ptlv.size() >= 2) {
|
||||
long delta = ptlv.get(ptlv.size() - 1) - ptlv.get(ptlv.size() - 2);
|
||||
long deltaxnanos = (long) (delta * 1000000000.0 / (1L << 32));
|
||||
if (deltaxnanos > 0)
|
||||
delay = deltaxnanos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
long length = kpp.getTotalLength();
|
||||
UUID pid = val == null ? KLALBUtils.createGlobalUUID() : val;
|
||||
//monitor.getDownloadBandwidth().recordPacket(pid,0,1, delay);
|
||||
if(delay!=Long.MAX_VALUE / 1024) {
|
||||
monitor.recordDownloadDelay(delay);
|
||||
//System.out.println(name+" "+delay);
|
||||
}
|
||||
monitor.recordDownloadPacket((int)length);
|
||||
if (klalbController != null) {
|
||||
//klalbController.getLinkMonitor().getDownloadBandwidth().recordPacket(pid, (int) length,delay);
|
||||
klalbController.getLinkMonitor().recordDownloadPacket((int)length);
|
||||
}
|
||||
//});
|
||||
}
|
||||
} catch (StreamCorruptedException sce) {
|
||||
sce.printStackTrace();
|
||||
} catch (IOException | UnresolvedAddressException e) {
|
||||
if (debug)
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (kplink != null)
|
||||
kplink.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
tpk.unpark();
|
||||
}
|
||||
}
|
||||
public WatchDogTimer getWatchdog() {
|
||||
return watchdog;
|
||||
}
|
||||
public long getRTT() {
|
||||
return rtt;
|
||||
}
|
||||
public long getRTTMin() {
|
||||
return rttMin;
|
||||
}
|
||||
|
||||
}
|
||||
private ThreadParker tpk=new ThreadParker();
|
||||
|
||||
private StateManager stateManager;
|
||||
private MonitorUpdater monitorUpdater;
|
||||
private class MonitorUpdater implements Runnable{
|
||||
@Override
|
||||
public void run() {
|
||||
while (!closed) {
|
||||
status.updateReliability();
|
||||
monitor.update();
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
private RemoteSender sender;
|
||||
private RemoteReceiver receiver;
|
||||
private class StateManager implements Runnable {
|
||||
|
||||
private Thread currThread;
|
||||
@Override
|
||||
public void run() {
|
||||
currThread = Thread.currentThread();
|
||||
ReliabilityBackoffTimeClock coll = new ReliabilityBackoffTimeClock();
|
||||
while (true) {
|
||||
try {
|
||||
|
||||
if (socketAddress == null) {
|
||||
if (kplink.isClosed()) {
|
||||
close();
|
||||
break;
|
||||
}
|
||||
if (addressGroup == null) {
|
||||
byte[] addr = new byte[16];
|
||||
SecureRandom scr = new SecureRandom();
|
||||
scr.nextBytes(addr);
|
||||
addr[0] = (byte) 0x24;
|
||||
addr[1] = (byte) 0x86;
|
||||
addr[2] = 0;
|
||||
addr[3] = 2;
|
||||
addr[14] = 0;
|
||||
addr[15] = 1;
|
||||
IPv6Address i6a = IPv6Address.valueOf(addr);
|
||||
addressGroup = new IPv6AddressGroup(i6a, 112);
|
||||
}
|
||||
} else {
|
||||
kplink = KLALBUtils.createKLALBPacketLink(bindAddress, socketAddress, true);
|
||||
}
|
||||
// startRecord();
|
||||
|
||||
kplink.setSoTimeout(3000);
|
||||
|
||||
|
||||
algorithm=getCongestionAlgorithm();
|
||||
sender = new RemoteSender();
|
||||
receiver = new RemoteReceiver();
|
||||
|
||||
|
||||
|
||||
sendWindow = new SendPacketSlidingWindow<UUID, IPv6Packet>(algorithm, 65535, HEADER_CALIBRATE);
|
||||
sendWindow.setResendConsumer(rerouteConsumer);
|
||||
sendWindow.setClosingConsumer(rerouteConsumer);
|
||||
algorithm.setWindowControlConsumer((sendwindow) -> {
|
||||
sendWindow.setWindowSize(sendwindow);
|
||||
});
|
||||
|
||||
Thread t = ThreadTool.makeVDaemonThreadIfSupport("远程发送线程", sender);
|
||||
t.start();
|
||||
|
||||
int cores = Runtime.getRuntime().availableProcessors();
|
||||
for (int i = 0; i < 1; i++) {
|
||||
ThreadTool.makeVDaemonThreadIfSupport("远程接收线程", receiver).start();
|
||||
}
|
||||
|
||||
while (!kplink.isClosed()) {
|
||||
if(klalbController!=null&& klalbController.getConfigItem()!=null) {
|
||||
KLALBControllerConfigItem config=klalbController.getConfigItem();
|
||||
if(algorithm instanceof DetnetCongestionAlgorithm) {
|
||||
double v0=config.getBurstLimit();
|
||||
if(v0!=0) {
|
||||
((DetnetCongestionAlgorithm)algorithm).setBurstLimit(v0);
|
||||
}
|
||||
double v1=config.getDelayUpperBound();
|
||||
if(v1!=0) {
|
||||
((DetnetCongestionAlgorithm)algorithm).setUpperDelayBound(v1);
|
||||
}
|
||||
double v2=config.getDelayLowerBound();
|
||||
if(v2!=0) {
|
||||
((DetnetCongestionAlgorithm)algorithm).setLowerDelayBound(v2);
|
||||
}
|
||||
}
|
||||
sender.setFlushInterval( config.getLinkNagleDelayTime());
|
||||
|
||||
|
||||
}
|
||||
boolean b = sender.getWatchdog().isBarking()
|
||||
|| receiver.getWatchdog().isBarking();
|
||||
boolean isup= (!b)&&(receiver.getRTT()<1000000000L);//&&(receiver.getRTT()<receiver.getRTTMin()*5+50000000L)
|
||||
int oldstate=status.getState();
|
||||
int newstate=isup?LinkStatus.UP:LinkStatus.UNSTABLE;
|
||||
status.setState(newstate);
|
||||
if(oldstate!=newstate) {
|
||||
onOnlineStateUpdate();
|
||||
}
|
||||
tpk.parkNanos(10000000L);
|
||||
}
|
||||
} catch (StreamCorruptedException sce) {
|
||||
sce.printStackTrace();
|
||||
} catch (IOException | UnresolvedAddressException e) {
|
||||
if (debug)
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
status.setState(LinkStatus.DOWN);
|
||||
try {
|
||||
if (kplink != null)
|
||||
kplink.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (sendWindow != null)
|
||||
sendWindow.close();
|
||||
onOnlineStateUpdate();
|
||||
}
|
||||
|
||||
if (closed) {
|
||||
break;
|
||||
}
|
||||
LockSupport.parkNanos(coll.getCoolingTime(status.getReliability()));
|
||||
|
||||
}
|
||||
}
|
||||
private CongestionAlgorithm getCongestionAlgorithm() {
|
||||
if(klalbController!=null&& klalbController.getConfigItem()!=null) {
|
||||
KLALBControllerConfigItem config=klalbController.getConfigItem();
|
||||
String cong=config.getCongestionAlgorithm();
|
||||
if(cong!=null) {
|
||||
CongestionAlgorithm alg=CongestionAlgorithms.get(cong);
|
||||
if(alg==null) {
|
||||
alg=new BBRCongestionAlgorithm();
|
||||
}
|
||||
return alg;
|
||||
}else {
|
||||
return new BBRCongestionAlgorithm();
|
||||
}
|
||||
}else {
|
||||
return new BBRCongestionAlgorithm();
|
||||
}
|
||||
}
|
||||
public void reconnectImmediately() {
|
||||
LockSupport.unpark(currThread);
|
||||
}
|
||||
public RemoteSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
public RemoteReceiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void startIO() {
|
||||
stateManager=new StateManager();
|
||||
monitorUpdater=new MonitorUpdater();
|
||||
ThreadTool.makeVDaemonThread("线路性能采样线程", monitorUpdater).start();
|
||||
ThreadTool.makeVDaemonThread("远程线路状态线程", stateManager).start();
|
||||
|
||||
}
|
||||
|
||||
public void ping() throws IOException {
|
||||
|
||||
PINGPacket ping = new PINGPacket(sysclk.getCurrentTimeNTP64().longValue(), monitor.getOutSpeed(),
|
||||
monitor.getInSpeed());
|
||||
/*
|
||||
* Long128 local=sysclk.getCurrentTimeNanos(); BigInteger local128=
|
||||
* NTPTimestamps.nanosToNtp128BitTimestamp(local);
|
||||
* System.out.println("psnd0"+NTPTimestamps.nanosSince1970ToString(
|
||||
* NTPTimestamps.ntp128BitToNanosTimestamp( NTPTimestamps.inferNtp64To128(
|
||||
* ping.getTime(),local128))));
|
||||
*/
|
||||
sendPacket(ping);
|
||||
}
|
||||
|
||||
private KLALBPacket readKLALBPacketFromKPL() throws IOException {
|
||||
KLALBPacket packet = kplink.readKLALBPacket();
|
||||
debugShowPacket("RX", packet);
|
||||
if (packet != null) {
|
||||
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
private void writeKLALBPacketToKPL(KLALBPacket packet) throws IOException {
|
||||
if (packet instanceof TESTNPacket)
|
||||
System.err.println(packet);
|
||||
kplink.writeKLALBPacket(packet);
|
||||
|
||||
debugShowPacket("TX", packet);
|
||||
}
|
||||
|
||||
private void debugShowPacket(String label, KLALBPacket packet) {
|
||||
if (showpacket) {
|
||||
if (!(packet instanceof PINGPacket))
|
||||
if (!(packet instanceof PONGPacket))
|
||||
if (!(packet instanceof BWINFPacket))
|
||||
System.err.println(label + ":" + packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
closed = true;
|
||||
status.setState(LinkStatus.DOWN);
|
||||
try {
|
||||
if (kplink != null)
|
||||
kplink.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void sendPacket(KLALBPacket vaddrreqPacket) {
|
||||
sendPacket(vaddrreqPacket, null);
|
||||
}
|
||||
|
||||
protected void sendPacket(KLALBPacket blk, UUID val) {
|
||||
debugShowPacket("TX", blk);
|
||||
RemoteSender sender=stateManager.getSender();
|
||||
if(sender!=null) {
|
||||
blk.markJoinqueuetime();
|
||||
long length = blk.getTotalLength();
|
||||
UUID pid = val == null ? KLALBUtils.createGlobalUUID() : val;
|
||||
monitor.recordUploadPacket((int) length);
|
||||
if (klalbController != null) {
|
||||
klalbController.getLinkMonitor().recordUploadPacket((int) length);
|
||||
}
|
||||
sender.sendDirect(blk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void reconnectImmediately() {
|
||||
StateManager stateManagerx=stateManager;
|
||||
if (stateManagerx != null) {
|
||||
stateManagerx.reconnectImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
public void dislink() {
|
||||
if (kplink != null) {
|
||||
try {
|
||||
kplink.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoopBack() {
|
||||
return false;
|
||||
}
|
||||
BandwidthDistributer bandwidthDistributer=new BandwidthDistributer<>();
|
||||
@Override
|
||||
public List<Neighbor> getNeighborsInfo() {
|
||||
List<Neighbor> hs = new ArrayList<>(1);
|
||||
if (peerAddress != null) {
|
||||
hs.add(new Neighbor(peerAddress, remoteVaddr, monitor, bandwidthDistributer));
|
||||
}
|
||||
return hs;
|
||||
}
|
||||
|
||||
|
||||
private Consumer<IPv6Packet> rerouteConsumer;
|
||||
|
||||
@Override
|
||||
public void sendPacket(IPv6Packet pack, IPv6Address inet6Address) throws IOException {
|
||||
// 只有已连接的链路才能传输数据
|
||||
if (status.getState() == LinkStatus.UP) {
|
||||
|
||||
IPv6HopByHopHeader hop = pack.getHopByHopHeader();
|
||||
|
||||
UUID val = null;
|
||||
if (hop != null) {
|
||||
List<IPv6HopByHopTLV> l = hop.getTlvs();
|
||||
for (int i = 0; i < l.size(); i++) {
|
||||
IPv6HopByHopTLV tlv = l.get(i);
|
||||
if (tlv instanceof KLALBOAMHopByHopTLV) {
|
||||
KLALBOAMHopByHopTLV seqs = (KLALBOAMHopByHopTLV) tlv;
|
||||
// 获得数据包的序号
|
||||
val = seqs.getUUID();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (val != null) {
|
||||
//if (!(pack.getPayload() instanceof ICMPv6PostcardPacket)) {
|
||||
// 放入滑动窗口中并记录缓冲区大小占用
|
||||
sendWindow.put(val, pack);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
sendIPv6PacketToLink(pack, val);
|
||||
|
||||
|
||||
} else {
|
||||
if (rerouteConsumer != null) {
|
||||
rerouteConsumer.accept(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer) {
|
||||
this.rerouteConsumer = rerouteConsumer;
|
||||
}
|
||||
|
||||
private void sendIPv6PacketToLink(IPv6Packet pack, UUID val) {
|
||||
IPv6OverKLALBPacket kipv6 = new IPv6OverKLALBPacket(pack);
|
||||
sendPacketToLink(kipv6, val);
|
||||
}
|
||||
|
||||
private void sendPacketToLink(KLALBPacket packet, UUID val) {
|
||||
sendPacket(packet, val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCongestion(IPv6Packet iPv6Packet, double scale) {
|
||||
SendPacketSlidingWindow<UUID, IPv6Packet> sw = sendWindow;
|
||||
if (sw != null) {
|
||||
return sw.isCongestion( scale);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isUp() {
|
||||
return (!isClosed()) && (status.getState() == LinkStatus.UP) ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RouteItem> getRouteItems() {
|
||||
List<RouteItem> rlist = new ArrayList<>();
|
||||
|
||||
IPv6AddressGroup adg = addressGroup;
|
||||
/*if (adg != null)
|
||||
rlist.add(new RouteItem(new IPv6AddressGroup(adg.getAddress(), 128), adg.getAddress(), this, "Direct", 0, 0,
|
||||
null, "D", true));*/
|
||||
|
||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo().iterator(); iteratorx.hasNext();) {
|
||||
Neighbor addresses = (Neighbor) iteratorx.next();
|
||||
RouteItem ri = new RouteItem(new IPv6AddressGroup(addresses.getAddress().getAddress(), 128),
|
||||
addresses.getAddress().getAddress(), this, "Direct", 0, 128,CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(),status,algorithm::getRTO), "D", false);
|
||||
rlist.add(ri);
|
||||
|
||||
if (addresses.getLocator() != null) {
|
||||
RouteItem ris = new RouteItem(addresses.getLocator(), addresses.getLocator().getAddress(), this,
|
||||
"KLALB SRv6", 13, 128,CostSupplierFactory.expectedDelaySupplier((DelayMonitorData) addresses.getMonitor(),status,algorithm::getRTO), "D", false);
|
||||
rlist.add(ris);
|
||||
}
|
||||
}
|
||||
return rlist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCongressCondition(Lock lock, Condition condition) {
|
||||
if (sendWindow != null)
|
||||
sendWindow.setCongressCondition(lock, condition);
|
||||
}
|
||||
|
||||
public void onPostcardReceive(PostcardEntry postcard) {
|
||||
long deltaxnanos = (long) (postcard.getTimestampDeltaLong() * 1000000000.0 / (1L << 32));
|
||||
if (deltaxnanos > 0) {
|
||||
Long128 psnd = NTPTimestamps.ntp128BitToNanosTimestamp(
|
||||
NTPTimestamps.inferNtp64To128(postcard.getTimestampBase(), sysclk.getCurrentTimeNTP128()));
|
||||
monitor.recordUploadDelay(deltaxnanos);
|
||||
}
|
||||
sendWindow.ack(postcard.getPacketUUID(),false,deltaxnanos);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public int getState() {
|
||||
return status.getState();
|
||||
}
|
||||
|
||||
|
||||
public SendPacketSlidingWindow<UUID, IPv6Packet> getWindow() {
|
||||
return sendWindow;
|
||||
}
|
||||
|
||||
|
||||
public long getQueueUsed() {
|
||||
if(sender==null) {
|
||||
return 0;
|
||||
}
|
||||
return sender.getQueueUsed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user