package org.kne.cloud.network.srv6; import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import org.kne.acclerate.FastLib; import org.kne.cloud.network.NetworkPacket; import org.kne.cloud.network.ipv6.FlowSession; import org.kne.cloud.network.ipv6.IPv6NetworkLink; import org.kne.cloud.network.ipv6.IPv6Packet; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6DestinationHeader; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6ExtHeader; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6RoutingHeader; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6SegmentRoutingHeader; import org.kne.cloud.network.ipv6.IPv6TUNLoopbackNetworkLink; import org.kne.cloud.network.ipv6.Inet6AddressGroup; import org.kne.cloud.network.ipv6.Neighbor; import org.kne.cloud.network.ipv6.RouteItem; import org.kne.cloud.network.klalb.BindableKLALBPacketConsumer; import org.kne.cloud.network.klalb.KLALBController; import org.kne.cloud.network.klalb.KLALBRemoteLine; import org.kne.cloud.network.monitor.MonitorData; import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl; import org.kne.cloud.network.tun.TUNNetworkDevice; import org.kne.concurrent.HighPerformanceExecutor; import org.kne.io.KNEChannels; import org.pcap4j.packet.IcmpV6CommonPacket; import org.pcap4j.packet.IcmpV6TimeExceededPacket; import org.pcap4j.packet.IllegalRawDataException; import org.pcap4j.packet.IpV6ExtRoutingPacket; import org.pcap4j.packet.IpV6ExtRoutingPacket.IpV6ExtRoutingHeader; import org.pcap4j.packet.IpV6Packet; import org.pcap4j.packet.IpV6Packet.Builder; import org.pcap4j.packet.IpV6RoutingSourceRouteData; import org.pcap4j.packet.IpV6SimpleFlowLabel; import org.pcap4j.packet.IpV6SimpleTrafficClass; import org.pcap4j.packet.Packet; import org.pcap4j.packet.Packet.Header; import org.pcap4j.packet.TcpPacket; import org.pcap4j.packet.TcpPacket.TcpHeader; import org.pcap4j.packet.UnknownPacket; import org.pcap4j.packet.namednumber.IcmpV6Code; import org.pcap4j.packet.namednumber.IcmpV6Type; import org.pcap4j.packet.namednumber.IpNumber; import org.pcap4j.packet.namednumber.IpV6RoutingType; import org.pcap4j.packet.namednumber.IpVersion; import com.google.gson.internal.Pair; public class SRv6Router { private static final boolean debug = false; public static final int MTU = 9000; public static final IpV6RoutingType SRH_HEADER = new IpV6RoutingType((byte) 4, "SRH Header"); // private Listlinks=new ArrayList<>(); private List routeTabel = new ArrayList<>(); private List linkTabel = new CopyOnWriteArrayList<>(); public List getLinkTabel() { return linkTabel; } // private ConcurrentHashMapswis=new // ConcurrentHashMap<>(); private final LoopbackIPv6NetworkLink inLoopBack = new LoopbackIPv6NetworkLink(); //private final LoopbackIPv6NetworkLink inLoopBackSRv6; private final LoopbackIPv6NetworkLink hostLoopBack ; private class LoopbackIPv6NetworkLink implements IPv6NetworkLink { private Inet6AddressGroup loopbackAddress; public LoopbackIPv6NetworkLink() { super(); try { this.loopbackAddress=new Inet6AddressGroup( (Inet6Address) Inet6Address.getByName("::1"),128); } catch (UnknownHostException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } public LoopbackIPv6NetworkLink(Inet6Address loopbackAddress) { super(); this.loopbackAddress = new Inet6AddressGroup(loopbackAddress,128); } public Consumer getReceiveConsumer() { return receiveConsumer; } private Consumer receiveConsumer; @Override public void sendPacket(IPv6Packet pack, Inet6Address next) throws IOException { PacketConsumer pcm; if ((pcm = protocolNumberRegister.get(pack.getPayload().getProtocolNumber())) != null) { pcm.accept(pack); return; } } @Override public boolean isLoopBack() { return true; } @Override public List getNeighborsInfo() { List hs = new ArrayList<>(); return hs; } @Override public boolean isCongress(IPv6Packet iPv6Packet) { return false; } @Override public String getName() { return "inLoopBack"; } @Override public boolean isUp() { return true; } @Override public boolean canSend(IPv6Packet iPv6Packet) { //System.out.println(iPv6Packet.getPayload().getProtocolNumber()); return protocolNumberRegister.containsKey(iPv6Packet.getPayload().getProtocolNumber()); } @Override public void setReceiveConsumer(Consumer con) { this.receiveConsumer = con; } @Override public Inet6AddressGroup getAddressGroup() { return loopbackAddress; } }; public List getRouteTabel() { return routeTabel; } public List getCurrentRouteTabel() { return routeTabel0; } private Consumer defaultReceive = new Consumer() { @Override public void accept(IPv6Packet t) { HighPerformanceExecutor.defaultExecutor.execute(() -> { routePacket(t); t.putTimePassport("routed"); }); } }; private Consumer srhReceive = new Consumer() { @Override public void accept(IPv6Packet t) { HighPerformanceExecutor.defaultExecutor.execute(() -> { insertSRHandRoutePacket(t); }); } }; public void updateRouteTabel() { List routeTabel0x = new ArrayList<>(); for (Iterator iterator = linkTabel.iterator(); iterator.hasNext();) { IPv6NetworkLink nlink = (IPv6NetworkLink) iterator.next(); if (nlink.isLoopBack()) { if (nlink instanceof IPv6TUNLoopbackNetworkLink) { routeTabel0x.add(new RouteItem(new Inet6AddressGroup(nlink.getAddressGroup().getAddress(), 128), nlink.getAddressGroup().getAddress(), nlink, "Direct", 0, 1, null, "D")); } else { routeTabel0x.add(new RouteItem(new Inet6AddressGroup(nlink.getAddressGroup().getAddress(), 128), nlink.getAddressGroup().getAddress(), nlink, "Direct", 0, 0, null, "D")); } }/*else { routeTabel0x.add(new RouteItem(new Inet6AddressGroup(nlink.getAddressGroup().getAddress(), 128), nlink.getAddressGroup().getAddress(), inLoopBack, "Direct", 0, 0, null, "D")); }*/ for (Iterator iteratorx = nlink.getNeighborsInfo() .iterator(); iteratorx.hasNext();) { Neighbor addresses = (Neighbor) iteratorx.next(); RouteItem ri = new RouteItem(new Inet6AddressGroup(addresses.getAddress().getAddress(), 128), addresses.getAddress().getAddress(), nlink, "Direct", 0, 128, addresses.getMonitor(), "D"); routeTabel0x.add(ri); RouteItem ris = new RouteItem(addresses.getLocator(), (Inet6Address) addresses.getLocator().getAddress(), nlink, "KLALB SRv6", 13, 128, addresses.getMonitor(), "D"); routeTabel0x.add(ris); } if (nlink instanceof IPv6TUNLoopbackNetworkLink) { nlink.setReceiveConsumer(srhReceive); } else { nlink.setReceiveConsumer(defaultReceive); } } routeTabel0x.addAll(routeTabel); Collections.sort(routeTabel0x); routeTabel0 = routeTabel0x; } private Inet6AddressGroup locator; /* * public List getLinks() { return links; } */ public Inet6AddressGroup getLocator() { return locator; } public void setLocator(Inet6AddressGroup locator) { this.locator = locator; updateRouteTabel(); } private ConcurrentHashMap swist = new ConcurrentHashMap<>(); // private AtomicLong qsn=new AtomicLong(); public void insertSRHandRoutePacket(IPv6Packet ipp) { insertSRH(ipp); ipp.putTimePassport("SRH inserted"); routePacket(ipp); ipp.putTimePassport("routed"); } public void insertSRH(IPv6Packet ipp) { if (klalbRouteProtol != null) { List segs = klalbRouteProtol.createSegmentList(ipp.getDestinationAddress()); // System.out.println(segs); if (segs != null && (!segs.isEmpty())) { /* * Listtlvs=new ArrayList<>(1); if(ipp.getPayload().getType()==6) { * SRv6StreamSequenceTLV sers= new SRv6StreamSequenceTLV(); * sers.setSequence(qsn.getAndIncrement()); tlvs.add(sers); } */ //IpV6RoutingSRHData srh = new IpV6RoutingSRHData(segs); IPv6SegmentRoutingHeader irh = new IPv6SegmentRoutingHeader(segs); ipp.getHeaders().add(irh); ipp.setDestinationAddress(segs.get(segs.size() - 1)); /* * if(ipp.getPayload().getType()==6) System.out.println(ipp); */ } } } private volatile List routeTabel0 = new ArrayList<>(); // private ReentrantReadWriteLock routelock=new ReentrantReadWriteLock(); public void routePacket(IPv6Packet iPv6Packet) { // routelock.readLock().lock(); // try { // System.out.println("路由表:"+routeTabel0); StringBuilder dbg=null; if (debug) { dbg=new StringBuilder(); } iPv6Packet.lockAll(); try { if(iPv6Packet.isSomeDisposed()) return; int hop = iPv6Packet.getHopLimit(); if (hop > 0) { // List mached=new ArrayList<>(); // RouteItem pri=null; Inet6Address ia = iPv6Packet.getDestinationAddress(); if (debug) { dbg.append("----------------------------------------\n"); dbg.append("packet:" + iPv6Packet.getSourceAddress().getHostAddress() + "->" + iPv6Packet.getDestinationAddress().getHostAddress()+"\n"); } for (int i = 0; i < routeTabel0.size(); i++) { RouteItem tri = routeTabel0.get(i); if (!tri.checkMatch(ia)) { if (debug) { dbg.append(tri+"\n"); dbg.append("unmatched.\n"); } continue; } if (!tri.getDestlink().isUp()) { if (debug) { dbg.append(tri+"\n"); dbg.append("linkdown.\n"); } continue; } if (tri.getDestlink().isCongress(iPv6Packet)) { if (debug) { dbg.append(tri+"\n"); dbg.append("congress.\n"); } continue; } if (!tri.getDestlink().canSend(iPv6Packet)) { if (debug) { dbg.append(tri+"\n"); dbg.append("linkrefused.\n"); } continue; } if (debug) { dbg.append(tri+"\n"); dbg.append("matched.\n"); } processPacket(iPv6Packet, tri); return; /* * if(pri==null||pri.equals(tri)) { mached.add(tri); pri=tri; }else { break; } */ } if (debug) { dbg.append("miss.\n"); } if (iPv6Packet.isEnableECN()) { iPv6Packet.markCE(); for (int i = 0; i < routeTabel0.size(); i++) { RouteItem tri = routeTabel0.get(i); if (tri.checkMatch(ia)) { if (!tri.getDestlink().isUp()) { continue; } processPacket(iPv6Packet, tri); return; /* * if(pri==null||pri.equals(tri)) { mached.add(tri); pri=tri; }else { break; } */ } } } if (debug) dbg.append("congress\n"); // System.out.println(ia.getAddress()+" match "+ri); /* * for (Iterator iterator = mached.iterator(); iterator.hasNext();) { RouteItem * routeItem = (RouteItem) iterator.next(); * if(routeItem.getDestlink().isCongress()) { * * }else { processPacket(iPv6Packet,pri); break; } } */ // else // System.out.println("路由失败:"+iPv6Packet); } else { IcmpV6TimeExceededPacket.Builder icmpte = new IcmpV6TimeExceededPacket.Builder(); ByteBuffer IPv6data = NetworkPacket.databufferpool_65535.borrow(); iPv6Packet.writeToChannel(KNEChannels.newWritableChannel(IPv6data)); byte[] raw = new byte[IPv6data.remaining()]; IPv6data.get(0, raw); icmpte.payload(IpV6Packet.newPacket(raw, 0, raw.length)); IcmpV6CommonPacket.Builder icbd = new IcmpV6CommonPacket.Builder(); icbd.type(IcmpV6Type.TIME_EXCEEDED); icbd.code(IcmpV6Code.HOP_LIMIT_EXCEEDED); icbd.srcAddr(locator.getAddress()); icbd.dstAddr(iPv6Packet.getSourceAddress()); icbd.correctChecksumAtBuild(true); icbd.payloadBuilder(icmpte); IPv6Packet icmpv = new IPv6Packet(); icmpv.setSourceAddress(locator.getAddress()); icmpv.setDestinationAddress(iPv6Packet.getSourceAddress()); icmpv.setTrafficClass(iPv6Packet.getTrafficClass()); icmpv.setVersion(6); icmpv.setFlowLabel(0); icmpv.setHopLimit(255); IPv6Payload ipl = new IPv6Payload(IpNumber.ICMPV6.value()); ipl.getData().put(icbd.build().getRawData()); ipl.getData().flip(); icmpv.setPayload(ipl); insertSRHandRoutePacket(icmpv); } } catch (Exception e) { e.printStackTrace(); }finally { if(debug) { System.out.println(dbg.toString()); } iPv6Packet.unlockAll(); } // }finally { // routelock.readLock().unlock(); // } } private void processPacket(IPv6Packet iPv6Packet, RouteItem ri) throws IllegalRawDataException, IOException { int hop = iPv6Packet.getHopLimit(); if (ri.getDestlink().isLoopBack()) { IPv6SegmentRoutingHeader srhh = getSRHHeaderFromPacket(iPv6Packet); if (srhh != null) { processSRv6Packet(iPv6Packet, ri, srhh); } else { ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop()); } } else { hop--; // System.out.println(ipp.getHeader().getSrcAddr()+"->"+ipp.getHeader().getDstAddr()+" // "+(hop+1)+"->"+hop); if (hop > 0) { iPv6Packet.setHopLimit(hop); ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop()); } else { IcmpV6TimeExceededPacket.Builder icmpte = new IcmpV6TimeExceededPacket.Builder(); ByteBuffer IPv6data = NetworkPacket.databufferpool_65535.borrow(); iPv6Packet.writeToChannel(KNEChannels.newWritableChannel(IPv6data)); byte[] raw = new byte[IPv6data.remaining()]; IPv6data.get(0, raw); icmpte.payload(IpV6Packet.newPacket(raw, 0, raw.length)); IcmpV6CommonPacket.Builder icbd = new IcmpV6CommonPacket.Builder(); icbd.type(IcmpV6Type.TIME_EXCEEDED); icbd.code(IcmpV6Code.HOP_LIMIT_EXCEEDED); icbd.srcAddr(locator.getAddress()); icbd.dstAddr(iPv6Packet.getSourceAddress()); icbd.correctChecksumAtBuild(true); icbd.payloadBuilder(icmpte); IPv6Packet icmpv = new IPv6Packet(); icmpv.setSourceAddress(locator.getAddress()); icmpv.setDestinationAddress(iPv6Packet.getSourceAddress()); icmpv.setTrafficClass(iPv6Packet.getTrafficClass()); icmpv.setVersion(6); icmpv.setFlowLabel(0); icmpv.setHopLimit(255); IPv6Payload ipl = new IPv6Payload(IpNumber.ICMPV6.value()); ipl.getData().put(icbd.build().getRawData()); ipl.getData().flip(); icmpv.setPayload(ipl); insertSRHandRoutePacket(icmpv); } } } private void processSRv6Packet(IPv6Packet iPv6Packet, RouteItem ri, IPv6SegmentRoutingHeader srhh) throws IllegalRawDataException, IOException { /*byte[] srd = new byte[(int) (srhh.getLength() - 4)]; srhh.getData().get(4, srd); IpV6RoutingSRHData srh = IpV6RoutingSRHData.newInstance(srd, 0, srd.length);*/ if (srhh.getSegmentsLeft() <= 0) { ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop()); } else { int newSL = srhh.getSegmentsLeft() - 1; srhh.setSegmentsLeft(newSL); iPv6Packet.setDestinationAddress(srhh.getAddresses().get(newSL)); klalbRouteProtol.putHotspotAddress(iPv6Packet.getSourceAddress()); routePacket(iPv6Packet); } } private IPv6SegmentRoutingHeader getSRHHeaderFromPacket(IPv6Packet iPv6Packet) { IPv6SegmentRoutingHeader srhh = null; List exhs = iPv6Packet.getHeaders(); for (int j = 0; j < exhs.size(); j++) { IPv6ExtHeader exh = exhs.get(j); if (exh instanceof IPv6SegmentRoutingHeader) { if (((IPv6SegmentRoutingHeader) exh).getRoutingType() == 4) { srhh = (IPv6SegmentRoutingHeader) exh; break; } } } return srhh; } public SRv6Router(Inet6AddressGroup hostAddress) { super(); this.locator = hostAddress; //this.inLoopBackSRv6=new LoopbackIPv6NetworkLink(locator.getAddress()); this.hostLoopBack= new LoopbackIPv6NetworkLink(hostAddress.getAddress()); linkTabel.add(inLoopBack); //linkTabel.add(inLoopBackSRv6); linkTabel.add(hostLoopBack); } /*public SRv6Router() { super(); linkTabel.add(inLoopBack); }*/ private KLALBRoutingProtocol klalbRouteProtol = null; public void runKLALBRouteProtocol() { if (klalbRouteProtol != null) throw new IllegalStateException("KLALB routing protocol is already running!"); klalbRouteProtol = new KLALBRoutingProtocol(this); klalbRouteProtol.start(); } public KLALBRoutingProtocol getKlalbRouteProtol() { return klalbRouteProtol; } private Map protocolNumberRegister = new ConcurrentHashMap<>(); public Map getProtocolNumberRegister() { return protocolNumberRegister; } public void putProtocolNumberPacketAndInsertSRH(IPv6Packet pkt) { // inLoopBack.getReceiveConsumer().accept(pkt); srhReceive.accept(pkt); } public void putProtocolNumberPacket(IPv6Packet pkt) { // inLoopBack.getReceiveConsumer().accept(pkt); defaultReceive.accept(pkt); } }