forked from KNEMC/KLALB
988 lines
29 KiB
Java
988 lines
29 KiB
Java
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();
|
|
}
|
|
|
|
|
|
|
|
}
|