package org.kne.cloud.network.srv6; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.BindException; import java.net.DatagramPacket; import java.net.Inet6Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.channels.Channels; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiConsumer; import org.kne.cloud.network.ipv6.IPv6Address; import org.kne.cloud.network.ipv6.IPv6NetworkLink; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6SegmentRoutingHeader; import org.kne.cloud.network.ipv6.IPv6AddressGroup; import org.kne.cloud.network.ipv6.Neighbor; import org.kne.cloud.network.klalb.KLALBVirtualRawSocket; import org.kne.cloud.network.monitor.DelayMonitorData; import org.kne.cloud.network.monitor.MonitorData; import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl; import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorData; import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl; import org.kne.membandboost.MembandBoost; public class KLALBRoutingProtocol extends Thread{ private static final boolean debug = false; private RouterInfo selfRouterInfo; private Map netmap=new ConcurrentHashMap<>(); public Map getNetmap() { return netmap; } private volatile Mapaddresses; private volatile Map> paths; public static final int DEFAULT_PORT=1001; public static final int DEFAULT_PROTOCOL_NUMBER=252; public static final long HOTSOPT_TIMEOUT = 1000000000; public static final int HOTSOPT_REPORT_INTERVAL = 1000000; private SRv6Router router; public SRv6Router getRouter() { return router; } public KLALBRoutingProtocol(SRv6Router router) { this.router=router; } //private ReentrantLock sendlock=new ReentrantLock(); private long floodTimer=System.nanoTime(); private long floodTimer2=System.nanoTime(); private long requestTimer=System.nanoTime(); private KLALBVirtualRawSocket ds = null; private ReentrantLock sendLock=new ReentrantLock(); private Set>receivers=new CopyOnWriteArraySet>(); public void addReceiver(BiConsumer rec) { receivers.add(rec); } public void removeReceiver(BiConsumer rec) { receivers.remove(rec); } @Override public void run() { Thread.currentThread().setName("KLALB路由协议接收线程"); getSelfRouterInfo(); try{ ds=new KLALBVirtualRawSocket(router.getinLoopback(),router.getLocator().getAddress().toInet6Address(), DEFAULT_PROTOCOL_NUMBER); new Thread(()->{ Thread.currentThread().setName("KLALB路由协议发送线程"); while(true) { try { selfRouterInfo = getSelfRouterInfo(); RouterInfo oslf=netmap.put(selfRouterInfo.getLocator().getAddress(), selfRouterInfo); noticeUpdate(); /*if(oslf==null||(!selfRouterInfo.equals(oslf))) { long cur=System.nanoTime(); if(cur-floodTimer2>5000000000L) { //System.out.println("update10"); floodTimer2=cur; floodPacket(ds2, null, new RouterInfoPacket(selfRouterInfo,true)); } }else { long cur=System.nanoTime(); if(cur-floodTimer>60000000000L) { //System.out.println("update60"); floodTimer=cur; floodPacket(ds2, null, new RouterInfoPacket(selfRouterInfo,true)); } }*/ long cur=System.nanoTime(); if(cur-floodTimer>20000000000L) { if(debug) System.out.println("update60"); floodTimer=cur; floodPacket( null, new RouterInfoPacket(selfRouterInfo,true,-1)); } if(cur-floodTimer2>2000000000L) { if(debug) System.out.println("update1"); floodTimer2=cur; floodPacket(null, new RouterInfoPacket(selfRouterInfo,true,router.getASN())); } //Set requestSet=new HashSet<>(); for (Iterator> iterator = netmap.entrySet().iterator(); iterator.hasNext();) { Entry type = (Entry) iterator.next(); RouterInfo val=type.getValue(); long timeout=30000000000L; if(val.getAsn()==router.getASN()) { timeout=2000000000L; } if(val.checkTimeOut(timeout)) { iterator.remove(); noticeUpdate(); } /*List ads=val.getNeighborAddresses(); for (Iterator iterator2 = ads.iterator(); iterator2.hasNext();) { Inet6Address address=iterator2.next().getLocator().getAddress(); //System.out.println(address); if(!netmap.containsKey(address)) { requestSet.add(address); } }*/ } computeShortestPathIfUpdated(); /*long cur2=System.nanoTime(); if(cur2-requestTimer>1000000000L) { requestTimer=cur2; for (Iterator iterator = requestSet.iterator(); iterator.hasNext();) { Inet6Address inet6Address = (Inet6Address) iterator.next(); writePacket(ds2, new RouterInfoRequestPacket( ), new InetSocketAddress(inet6Address, DEFAULT_PORT)); if(debug) System.out.println("Request:"+inet6Address); } }*/ for (Iterator> iterator = hotspots.entrySet().iterator(); iterator.hasNext();) { Entry type = (Entry) iterator.next(); //if(type.getValue().checkReportTime()) { //System.out.println("hotspot address:"+type.getKey()); //writePacket(ds2, new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(type.getKey(), DEFAULT_PORT)); //} if(type.getValue().checkTimeOut()) { iterator.remove(); } } Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); }catch (IOException e1) { // TODO 自动生成的 catch 块 e1.printStackTrace(); } } }).start(); while(true) { try { byte[]ca=MembandBoost.allocateUninitializedArray(65535); 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()) { case KLALBRoutingProtocolPacket.RINFO_REQ: RouterInfo rifr=netmap.get(router.getLocator().getAddress()); if(debug) System.out.println("get Request from:"+dgp.getSocketAddress()); if(rifr!=null) { writePacket( new RouterInfoPacket( rifr,false,-1), dgp.getSocketAddress()); if(debug) System.out.println("response router info:"+rifr); }else { if(debug) System.out.println("router info is null!"); } break; case KLALBRoutingProtocolPacket.RINFO: RouterInfoPacket rifp=(RouterInfoPacket) kp; RouterInfo rif=rifp.getRinfo(); RouterInfo oldrif=netmap.get(rif.getLocator().getAddress()); if(debug) System.out.println(rif); if(oldrif==null||oldrif.getCreateTime(){v.accept(dgp.getSocketAddress(),data);}); break; default: break; } } catch (IOException e) { e.printStackTrace(); } } } catch (SocketException e2) { e2.printStackTrace(); }finally { if(ds!=null) { ds.close(); } } } private void floodPacket(SocketAddress except,RouterInfoPacket rifp) throws IOException { long asn=rifp.getASN(); Listln= router.getNeighbors(); Setist=new HashSet(); for(Neighbor addresses :ln) { if(addresses.getLocator()==null) continue; InetSocketAddress isa=new InetSocketAddress(addresses.getLocator().getAddress().toInet6Address(),DEFAULT_PORT); if(!ist.add(isa)) { continue; } if(!isa.equals(except)) { if(asn==-1) { writePacket( rifp, isa); }else{ RouterInfo nif= netmap.get( IPv6Address.valueOf( isa.getAddress())); if(nif!=null&&nif.getAsn()==asn) { writePacket( rifp, isa); } } } } } public void sendJsonPacketToAddress(JsonDataPacket pkt,SocketAddress dest) throws IOException { writePacket(pkt,dest); } private void writePacket(KLALBRoutingProtocolPacket pkt,SocketAddress dest) throws IOException { ByteArrayOutputStream bos=new ByteArrayOutputStream(65535); KLALBRoutingProtocolPacket.writeKLALBPacketToChannel(Channels.newChannel(bos),pkt); byte[]to=bos.toByteArray(); DatagramPacket dgpx=new DatagramPacket(to,to.length); dgpx.setSocketAddress(dest); sendLock.lock(); try { ds.send(dgpx); }catch(BindException e) { e.printStackTrace(); System.err.println("Cannot assign:"+dest); }finally { sendLock.unlock(); } } private DijkstraAlgorithm algorithm=new SingleDijkstraAlgorithm(); private ReentrantLock directionLock=new ReentrantLock(); private volatile NetmapDirections directions; private static class NetmapDirections{ public NetmapDirections(long[] direction, List rias, Map direction_airs) { super(); this.direction = direction; this.direction_rias = rias; this.direction_airs = direction_airs; } public NetmapDirections(long[] direction, List rias, Map airs,Object obj) { this.direction = direction; this.direction_rias=new ArrayList(); rias.forEach((addr)->{ direction_rias.add(new IPv6Address(addr)); }); this.direction_airs=new HashMap<>(); airs.forEach((k,v)->{ direction_airs.put(new IPv6Address(k), v); }); } private long[] direction; private List direction_rias; private Map direction_airs; public long[] getDirection() { return direction; } public List getDirection_rias() { return direction_rias; } public Map getDirection_airs() { return direction_airs; } } private volatile boolean updated=false; public void noticeUpdate() { updated=true; } private void computeShortestPathIfUpdated() { if(updated) { computeShortestPath(); updated=false; } } private void computeShortestPath() { directionLock.lock(); try { if(netmap.get(router.getLocator().getAddress())==null) { return; } Set> s=netmap.entrySet(); Mapairs=new HashMap<>(netmap.size()*2,0.4f); Listrias=new ArrayList<>(netmap.size()+1); Map>paths=new HashMap<>(); long number=0; for(Entry entry:s) { if(!airs.containsKey(entry.getKey())) { airs.put(entry.getKey(),number); rias.add( entry.getKey()); number++; } List ni= entry.getValue().getNeighborAddresses(); for(NeighborInfo neighborInfo :ni) { IPv6Address ias2=neighborInfo.getLocator().getAddress(); if(!airs.containsKey(ias2)) { airs.put(ias2,number); rias.add( ias2); number++; } Listlp1=paths.get(entry.getKey()); if(lp1==null) { paths.put(entry.getKey(), lp1=new ArrayList<>()); } lp1.add(new LinkDirection(neighborInfo.getLocal(),neighborInfo.getNeighbor(),entry.getKey(), ias2, neighborInfo.getUploadDelay(),neighborInfo.getUploadDelayMin(),neighborInfo.getUploadSpeed(),neighborInfo.getUploadSpeedMax())); /*Setlp2=paths.get(ias2); if(lp2==null) { paths.put(ias2, lp2=new HashSet<>()); } lp2.add( new LinkDirection(neighborInfo.getNeighbor(),neighborInfo.getLocal(),ias2,entry.getKey() , neighborInfo.getDownloadDelay(),neighborInfo.getDownloadDelayMin(),neighborInfo.getDownloadSpeed(),neighborInfo.getDownloadSpeedMax())); */ } } long[][]pointers=new long[(int) airs.size()][2]; long heappos=0; long linknumber=0; for(Entry> entry:paths.entrySet()) { /*for (Iterator>> iterator = paths.entrySet().iterator(); iterator.hasNext();) { Entry> entry = (Entry>) iterator.next();*/ linknumber+=entry.getValue().size(); } long[][]heap=new long[(int) (linknumber)][2]; for (long i = 0; i < number; i++) { long heapindex=0; pointers[(int) i][0]=heappos; IPv6Address ia=rias.get((int) i); Listlks=paths.get(ia); if(lks!=null) for(LinkDirection linkPath:lks) { /* for (Iterator iterator = lks.iterator(); iterator.hasNext();) { LinkDirection linkPath=iterator.next();*/ heap[(int)(heappos+ heapindex)][0]=airs.get(linkPath.getToLocator()); heap[(int) (heappos+heapindex)][1]=linkPath.getWeight(); //heap[(int) (heappos+heapindex)][2]=linkPath.get // heap[(int) (heappos+heapindex)][3]=0; heapindex++; } heappos+=heapindex; pointers[(int) i][1]=heapindex; } algorithm.setGraph(pointers,heap,airs.get(router.getLocator().getAddress())); algorithm.run(); directions=new NetmapDirections(algorithm.getDirection(), rias, airs); addresses=airs; this.paths=paths; }finally { directionLock.unlock(); } //System.out.println(Arrays.toString( algorithm.getDirection())); } public static class LinkDirection{ private IPv6AddressGroup fromAddress; private IPv6AddressGroup toAddress; private IPv6Address fromLocator; private IPv6Address toLocator; private long delay; private long delayMin; private long speed; public long getSpeed() { return speed; } private long bandwidth; public IPv6AddressGroup getFromAddress() { return fromAddress; } public IPv6AddressGroup getToAddress() { return toAddress; } public long getDelay() { return delay; } public long getBandwidth() { return bandwidth; } public long getDelayMin() { return delayMin; } public LinkDirection(IPv6AddressGroup fromAddress, IPv6AddressGroup toAddress, IPv6Address fromLocator, IPv6Address toLocator, long delay, long delayMin, long speed, long bandwidth) { super(); this.fromAddress = fromAddress; this.toAddress = toAddress; this.fromLocator = fromLocator; this.toLocator = toLocator; this.delay = delay; this.delayMin = delayMin; this.speed = speed; this.bandwidth = bandwidth; } @Override public String toString() { return "LinkDirection [fromAddress=" + fromAddress + ", toAddress=" + toAddress + ", fromLocator=" + fromLocator + ", toLocator=" + toLocator + ", delay=" + delay + ", delayMin=" + delayMin + ", speed=" + speed + ", bandwidth=" + bandwidth + "]"; } public IPv6Address getFromLocator() { return fromLocator; } @Override public int hashCode() { return Objects.hash(fromAddress, toAddress); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; LinkDirection other = (LinkDirection) obj; return Objects.equals(fromAddress, other.fromAddress) && Objects.equals(toAddress, other.toAddress); } public IPv6Address getToLocator() { return toLocator; } public long getWeight() { return delay; } } private RouterInfo getSelfRouterInfo() { Listlinks=router.getLinkTabel(); Object[] nls=links.toArray(); RouterInfo ri=new RouterInfo(System.currentTimeMillis(),router.getLocator(),router.getASN()); ri.setDeviceName(router.getDeviceName()); for(int i=0;ineis=nl.getNeighborsInfo(); for (Iterator iteratorx = neis.iterator(); iteratorx.hasNext();) { Neighbor addresses = (Neighbor) iteratorx.next(); long updelay=10000000000L; long downdelay=10000000000L; long updelayMin=10000000000L; long downdelayMin=10000000000L; long uploadspeed=1024L*1024; long downloadspeed=1024L*1024; long uploadspeedmax=1024L*1024; long downloadspeedmax=1024L*1024; MonitorData md=addresses.getMonitor(); if(md!=null) { if(md instanceof DelayMonitorData) { updelay=((DelayMonitorData) md).getOutDelay(); downdelay=((DelayMonitorData) md).getInDelay(); if(md instanceof SpeedAndTrafficAndDelayMonitorDataImpl) { updelayMin=((SpeedAndTrafficAndDelayMonitorDataImpl) md).getOutDelayMin(); downdelayMin=((SpeedAndTrafficAndDelayMonitorDataImpl) md).getInDelayMin(); } } if(md instanceof SpeedAndTrafficMonitorData) { uploadspeed=((SpeedAndTrafficMonitorData) md).getOutSpeed(); downloadspeed=((SpeedAndTrafficMonitorData) md).getInSpeed(); if(md instanceof SpeedAndTrafficMonitorDataImpl) { SpeedAndTrafficMonitorDataImpl smd=(SpeedAndTrafficMonitorDataImpl) md; uploadspeedmax=smd.getOutSpeedMax(); downloadspeedmax=smd.getInSpeedMax(); } } } NeighborInfo ni=new NeighborInfo(nl.getAddressGroups().get(0),addresses.getAddress(),addresses.getLocator(),updelay ,downdelay,updelayMin ,downdelayMin ,uploadspeed ,downloadspeed,uploadspeedmax ,downloadspeedmax); ni.setContext(addresses); ri.getNeighborAddresses().add(ni); } } } //if(debug) //System.out.println(ri); return ri; } public Map getAddresses() { return addresses; } /** * 查询某地址广播的设备名称(未知返回null) */ public String getDeviceName(IPv6Address address) { RouterInfo ri=netmap.get(address); if(ri!=null) { String dn=ri.getDeviceName(); if(dn!=null&&!dn.isEmpty()) return dn; } return null; } public Map> getPaths() { return paths; } public IPv6SegmentRoutingHeader createSegmentList(IPv6Address dest) { NetmapDirections directionsx=directions; if(directionsx==null) { return null; } Long dn=directionsx.getDirection_airs().get(dest); if(dn==null) { return null; } IPv6SegmentRoutingHeader segs=new IPv6SegmentRoutingHeader(); Listsegments=segs.getAddresses(); while(true) { long idx=directionsx.getDirection()[(int) dn.longValue()]; if(idx==-1) { return null; } if(idx==dn) { segs. resetSegmentPos(); return segs; } segments.add(directionsx.getDirection_rias().get(dn.intValue())); dn=idx; } } public long getDevicesFound() { return netmap.size(); } private static class HotspotAddressTimer{ private long putTime=System.nanoTime(); private long reportTime =System.nanoTime(); public boolean checkTimeOut() { return System.nanoTime()-putTime>HOTSOPT_TIMEOUT; } public boolean checkReportTime() { long cu = System.nanoTime(); if (cu - reportTime > HOTSOPT_REPORT_INTERVAL) { reportTime = cu; return true; } else { return false; } } public void refreshTimeout() { putTime=System.nanoTime(); } } private Map hotspots=new ConcurrentHashMap<>(); public void putHotspotAddress(IPv6Address iPv6Address) { if(true) { HotspotAddressTimer hat=hotspots.get(iPv6Address); if(hat==null) { hotspots.put(iPv6Address,hat= new HotspotAddressTimer()); }else { hat.refreshTimeout(); } if(hat.checkReportTime()) { //System.out.println("hotspot address:"+sourceAddress); /* try { writePacket( new RouterInfoPacket( netmap.get(router.getLocator().getAddress()),false,-1), new InetSocketAddress(iPv6Address.toInet6Address(), DEFAULT_PORT)); } catch (IOException e) { e.printStackTrace(); }*/ } } } private Map toIpBandwidth=new ConcurrentHashMap(); public void updateTotalRequestBandwidth(IPv6Address targetaAddress, Long treq) { Objects.requireNonNull(targetaAddress); //System.out.println("到"+targetaAddress.getHostAddress()+"请求带宽更新:"+treq); if(treq<=0) { if(toIpBandwidth.remove(targetaAddress)!=null) { noticeUpdate(); } }else { Long old=toIpBandwidth.put(targetaAddress, treq); if(old==null||old.longValue()!=treq.longValue()) { noticeUpdate(); } } } public IPv6Address getDijkstraPrevNode(IPv6Address text) { NetmapDirections directionsx=directions; if(directionsx==null) return null; Long l=directionsx.getDirection_airs().get(text); if(l==null) return null; long number= l; long prev= directionsx.getDirection()[(int)number]; if(prev==-1) { return null; } return directionsx.getDirection_rias().get((int) prev); } }