Files
KLALB/src/org/kne/cloud/network/srv6/SRv6Router.java
T

570 lines
18 KiB
Java

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 List<NetworkLink>links=new ArrayList<>();
private List<RouteItem> routeTabel = new ArrayList<>();
private List<IPv6NetworkLink> linkTabel = new CopyOnWriteArrayList<>();
public List<IPv6NetworkLink> getLinkTabel() {
return linkTabel;
}
// private ConcurrentHashMap<FlowSession,SlidingWindowInformation>swis=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<IPv6Packet> getReceiveConsumer() {
return receiveConsumer;
}
private Consumer<IPv6Packet> 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<Neighbor> getNeighborsInfo() {
List<Neighbor> 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<IPv6Packet> con) {
this.receiveConsumer = con;
}
@Override
public Inet6AddressGroup getAddressGroup() {
return loopbackAddress;
}
};
public List<RouteItem> getRouteTabel() {
return routeTabel;
}
public List<RouteItem> getCurrentRouteTabel() {
return routeTabel0;
}
private Consumer<IPv6Packet> defaultReceive = new Consumer<IPv6Packet>() {
@Override
public void accept(IPv6Packet t) {
HighPerformanceExecutor.defaultExecutor.execute(() -> {
routePacket(t);
t.putTimePassport("routed");
});
}
};
private Consumer<IPv6Packet> srhReceive = new Consumer<IPv6Packet>() {
@Override
public void accept(IPv6Packet t) {
HighPerformanceExecutor.defaultExecutor.execute(() -> {
insertSRHandRoutePacket(t);
});
}
};
public void updateRouteTabel() {
List<RouteItem> routeTabel0x = new ArrayList<>();
for (Iterator<IPv6NetworkLink> 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<Neighbor> 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<NetworkLink> getLinks() { return links; }
*/
public Inet6AddressGroup getLocator() {
return locator;
}
public void setLocator(Inet6AddressGroup locator) {
this.locator = locator;
updateRouteTabel();
}
private ConcurrentHashMap<FlowSession, TCPTransimitAgent> 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<Inet6Address> segs = klalbRouteProtol.createSegmentList(ipp.getDestinationAddress());
// System.out.println(segs);
if (segs != null && (!segs.isEmpty())) {
/*
* List<SRv6TLV>tlvs=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<RouteItem> 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<RouteItem> 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<IPv6ExtHeader> 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<Integer, PacketConsumer> protocolNumberRegister = new ConcurrentHashMap<>();
public Map<Integer, PacketConsumer> 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);
}
}