forked from KNEMC/KLALB
768 lines
23 KiB
Java
768 lines
23 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.security.SecureRandom;
|
||
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.UUID;
|
||
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.ThreadLocalRandom;
|
||
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.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 = 8192;
|
||
|
||
public static final int MAX_REROUTE_COUNT=2;//1
|
||
|
||
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,double scale) {
|
||
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;
|
||
}
|
||
|
||
@Override
|
||
public void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer) {
|
||
// TODO 自动生成的方法存根
|
||
|
||
}
|
||
|
||
@Override
|
||
public List<RouteItem> getRouteItems() {
|
||
List<RouteItem> rlist=new ArrayList<>();
|
||
|
||
rlist.add(new RouteItem(new Inet6AddressGroup(this.getAddressGroup().getAddress(), 128),
|
||
this.getAddressGroup().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 Inet6AddressGroup(addresses.getAddress().getAddress(), 128), addresses.getAddress().getAddress(),
|
||
this, "Direct", 0, 128, addresses.getMonitor(), "D",false);
|
||
rlist.add(ri);
|
||
|
||
RouteItem ris = new RouteItem(addresses.getLocator(), (Inet6Address) addresses.getLocator().getAddress(),
|
||
this, "KLALB SRv6", 13, 128, addresses.getMonitor(), "D",false);
|
||
rlist.add(ris);
|
||
|
||
}
|
||
return rlist;
|
||
}
|
||
|
||
@Override
|
||
public boolean isReachSpeedLimit(IPv6Packet iPv6Packet) {
|
||
return false;
|
||
}
|
||
|
||
|
||
};
|
||
|
||
public List<RouteItem> getRouteTabel() {
|
||
return routeTabel;
|
||
}
|
||
|
||
public List<RouteItem> getCurrentRouteTabel() {
|
||
return routeTabel0;
|
||
}
|
||
|
||
|
||
private Consumer<IPv6Packet> defaultReroute = new Consumer<IPv6Packet>() {
|
||
|
||
@Override
|
||
public void accept(IPv6Packet t) {
|
||
//HighPerformanceExecutor.defaultExecutor.execute(() -> {
|
||
routePacket(t,true);
|
||
t.putTimePassport("rerouted");
|
||
//});
|
||
}
|
||
};
|
||
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);
|
||
//});
|
||
}
|
||
};
|
||
|
||
private volatile UUID suid=UUID.randomUUID();
|
||
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"));
|
||
|
||
}
|
||
}
|
||
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);
|
||
|
||
}*/
|
||
|
||
List<RouteItem>routes=nlink.getRouteItems();
|
||
|
||
routeTabel0x.addAll(routes);
|
||
|
||
if (nlink instanceof IPv6TUNLoopbackNetworkLink) {
|
||
|
||
nlink.setReceiveConsumer(srhReceive);
|
||
} else {
|
||
nlink.setReceiveConsumer(defaultReceive);
|
||
}
|
||
nlink.setRerouteConsumer(defaultReroute);
|
||
}
|
||
|
||
/*List<RouteItem> routeTabel1x=new ArrayList<>(routeTabel0x.size());
|
||
|
||
routeTabel0x.addAll(routeTabel);
|
||
for (Iterator<RouteItem> iterator = routeTabel0x.iterator(); iterator.hasNext();) {
|
||
RouteItem routeItem = (RouteItem) iterator.next();
|
||
routeTabel1x.add((RouteItem) routeItem.clone());
|
||
}*/
|
||
for (Iterator<RouteItem> iterator = routeTabel0x.iterator(); iterator.hasNext();) {
|
||
RouteItem routeItem = (RouteItem) iterator.next();
|
||
routeItem.preSort();
|
||
|
||
}
|
||
Collections.sort(routeTabel0x);
|
||
routeTabel0 = routeTabel0x;
|
||
suid=UUID.randomUUID();
|
||
}
|
||
|
||
private Inet6AddressGroup locator;
|
||
private long asn=new SecureRandom().nextLong(1,Long.MAX_VALUE);
|
||
/*
|
||
* public List<NetworkLink> getLinks() { return links; }
|
||
*/
|
||
|
||
|
||
|
||
|
||
public Inet6AddressGroup getLocator() {
|
||
return locator;
|
||
}
|
||
|
||
public long getASN() {
|
||
return asn;
|
||
}
|
||
|
||
public void setASN(long asn) {
|
||
this.asn = asn;
|
||
}
|
||
|
||
public void setLocator(Inet6AddressGroup locator) {
|
||
this.locator = locator;
|
||
updateRouteTabel();
|
||
}
|
||
|
||
|
||
//private ConcurrentHashMap<FlowSession, TCPTransimitAgent> swist = new ConcurrentHashMap<>();
|
||
|
||
public void insertSRHandRoutePacket(IPv6Packet ipp) {
|
||
insertSRH(ipp);
|
||
ipp.putTimePassport("SRH inserted");
|
||
routePacket(ipp);
|
||
ipp.putTimePassport("routed");
|
||
}
|
||
|
||
|
||
public void insertSRH(IPv6Packet ipp) {
|
||
if(ipp.getSRHHeader()!=null) {
|
||
throw new IllegalStateException("packet already has SRH!");
|
||
}
|
||
if (klalbRouteProtol != null) {
|
||
List<Inet6Address> segs = klalbRouteProtol.createSegmentList(ipp.getDestinationAddress());
|
||
// System.out.println(segs);
|
||
if (segs != null && (!segs.isEmpty())) {
|
||
|
||
IPv6SegmentRoutingHeader irh = new IPv6SegmentRoutingHeader(segs);
|
||
|
||
//System.out.println(ipp.getFlowLabel());
|
||
ThreadLocalRandom tlr=ThreadLocalRandom.current();
|
||
//System.out.println(ipp.getFlowSeqMark());
|
||
irh.getTlvs().add(new SEQSSegmentRoutingTLV(ipp.getFlowSeqMark(),new UUID(suid.getMostSignificantBits()^tlr.nextLong(),suid.getMostSignificantBits()^tlr.nextLong()),ipp.isPromise(),ipp.getFlowSeqMark()!=-1));
|
||
|
||
ipp.getHeaders().add(irh);
|
||
|
||
ipp.setDestinationAddress(segs.get(segs.size() - 1));
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
private volatile List<RouteItem> routeTabel0 = new ArrayList<>();
|
||
|
||
// private ReentrantReadWriteLock routelock=new ReentrantReadWriteLock();
|
||
|
||
|
||
//路由数据包
|
||
public void routePacket(IPv6Packet iPv6Packet) {
|
||
routePacket(iPv6Packet ,false);
|
||
}
|
||
//路由数据包
|
||
public void routePacket(IPv6Packet iPv6Packet, boolean reroute) {
|
||
// routelock.readLock().lock();
|
||
// try {
|
||
// System.out.println("路由表:"+routeTabel0);
|
||
StringBuilder dbg=null;
|
||
if (debug) {
|
||
dbg=new StringBuilder();
|
||
}
|
||
try {
|
||
int hop = iPv6Packet.getHopLimit();//检查TTL值,只有大于0才会被转发,否则丢弃
|
||
if (hop > 0) {
|
||
// List<RouteItem> mached=new ArrayList<>();
|
||
// RouteItem pri=null;
|
||
|
||
|
||
//按延迟顺序从小到大匹配路由表
|
||
if(searchTableAndFoward(iPv6Packet, reroute, dbg)) {
|
||
//匹配到路由表,返回
|
||
return ;
|
||
}
|
||
|
||
|
||
if (debug)
|
||
dbg.append("noroute\n");
|
||
//System.out.println("找不到路由表:"+iPv6Packet.getSourceAddress().getHostAddress()+" -> "+iPv6Packet.getDestinationAddress().getHostAddress());
|
||
|
||
//未找到合适的路由表或路由表对应的链路down,使用FRR保护创建备用路由表
|
||
IPv6SegmentRoutingHeader srh=iPv6Packet.getSRHHeader();
|
||
if(srh!=null) {
|
||
System.out.println("原SRH:"+srh);
|
||
int segmentsLeft=srh.getSegmentsLeft();
|
||
if(segmentsLeft>0) {
|
||
srh.getAddresses().remove(segmentsLeft);
|
||
segmentsLeft--;
|
||
}
|
||
List<Inet6Address> repairSegments= klalbRouteProtol.createSegmentList(srh.getAddresses().get(segmentsLeft));
|
||
if(repairSegments ==null) {
|
||
System.out.println("FRR保护失败");
|
||
return;
|
||
}
|
||
repairSegments.remove(0);
|
||
srh.getAddresses().addAll(segmentsLeft+1, repairSegments);
|
||
segmentsLeft+=repairSegments.size();
|
||
srh.setSegmentsLeft(segmentsLeft);
|
||
iPv6Packet.setDestinationAddress(srh.getAddresses().get(segmentsLeft));
|
||
}else {
|
||
return;
|
||
}
|
||
System.out.println("FRR修复SRH:"+srh);
|
||
if(searchTableAndFoward(iPv6Packet, reroute, dbg)) {
|
||
return ;
|
||
}
|
||
|
||
|
||
} else {
|
||
IcmpV6TimeExceededPacket.Builder icmpte = new IcmpV6TimeExceededPacket.Builder();
|
||
ByteBuffer IPv6data = NetworkPacket.bufferAllocator.allocate(65535);
|
||
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());
|
||
}
|
||
}
|
||
// }finally {
|
||
// routelock.readLock().unlock();
|
||
// }
|
||
}
|
||
|
||
private boolean searchTableAndFoward(IPv6Packet iPv6Packet, boolean reroute, StringBuilder dbg)
|
||
throws IllegalRawDataException, IOException {
|
||
byte[] ia = new byte[16];
|
||
iPv6Packet.getRawDestinationAddress(ia);
|
||
if (debug) {
|
||
dbg.append("----------------------------------------\n");
|
||
dbg.append("packet:" + iPv6Packet.getSourceAddress().getHostAddress() + " -> "
|
||
+ iPv6Packet.getDestinationAddress().getHostAddress()+"\n");
|
||
}
|
||
|
||
boolean routeFound=false;
|
||
|
||
RouteItem prevr=null;
|
||
List<RouteItem> routes=new ArrayList<>();
|
||
//遍历路由表
|
||
for (RouteItem tri: routeTabel0) {
|
||
if(!tri.checkMatch(ia)) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("unmatched.\n");
|
||
}
|
||
//跳过前缀与掩码不符合要求的路由表条目
|
||
continue;
|
||
}
|
||
if (!tri.getDestlink().canSend(iPv6Packet)) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("linkrefused.\n");
|
||
}
|
||
//跳过不能转发这种数据包的链路
|
||
continue;
|
||
}
|
||
if (!tri.getDestlink().isUp()) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("linkdown.\n");
|
||
}
|
||
//跳过断开连接的链路
|
||
continue;
|
||
}
|
||
routeFound=true;
|
||
if(prevr!=null) {
|
||
if(!tri.ECMPequals(prevr)) {
|
||
//执行流量整形负载均衡调度算法
|
||
if(routingLoadBalance(iPv6Packet, reroute, dbg, routes)) {
|
||
return routeFound;
|
||
}
|
||
routes.clear();
|
||
}
|
||
}
|
||
//将等价路由加入负载均衡列表
|
||
routes.add(tri);
|
||
|
||
prevr=tri;
|
||
|
||
|
||
|
||
}
|
||
routingLoadBalance(iPv6Packet, reroute, dbg, routes);
|
||
return routeFound;
|
||
}
|
||
|
||
private boolean routingLoadBalance(IPv6Packet iPv6Packet, boolean reroute, StringBuilder dbg, List<RouteItem> routes)
|
||
throws IllegalRawDataException, IOException {
|
||
|
||
double cscale=1.0;
|
||
if(iPv6Packet.getPayload().getProtocolNumber()==6) {
|
||
cscale=15.0;
|
||
}
|
||
|
||
boolean retry=false;
|
||
long start=System.nanoTime();
|
||
do {
|
||
retry=false;
|
||
//遍历可用于负载均衡调度的路由表
|
||
for (RouteItem tri: routes) {
|
||
if (!tri.getDestlink().isUp()) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("linkdown.\n");
|
||
}
|
||
//跳过断开的链路
|
||
continue;
|
||
}
|
||
if (tri.getDestlink().isCongress(iPv6Packet,cscale)) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("congress.\n");
|
||
}
|
||
//跳过缓冲区拥塞的链路
|
||
continue;
|
||
}
|
||
|
||
if (tri.getDestlink().isReachSpeedLimit(iPv6Packet)) {
|
||
retry=true;
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("reachspeedlimit.\n");
|
||
}
|
||
//跳过达到流量整形速度限制的链路(若仅超过流量整形速度限制,可多次重试)
|
||
continue;
|
||
}
|
||
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("matched.\n");
|
||
}
|
||
//链路可用,处理并转发数据包
|
||
processPacket(iPv6Packet, tri,reroute);
|
||
return true;
|
||
|
||
}
|
||
if(retry) {
|
||
if(System.nanoTime()-start>200000000L) {
|
||
break;
|
||
}
|
||
try {
|
||
Thread.sleep(1);
|
||
} catch (InterruptedException e) {
|
||
e.printStackTrace();
|
||
}
|
||
//Thread.yield();
|
||
//短暂挂起当前线程,待链路速度未超限时重试发送数据包
|
||
}
|
||
}while((!routes.isEmpty())&&retry);
|
||
if (debug) {
|
||
dbg.append("miss.\n");
|
||
}
|
||
//负载均衡未匹配成功,若数据包支持ECN,打上拥塞标记位
|
||
if(iPv6Packet.isEnableECN()) {
|
||
iPv6Packet.markCE();
|
||
if (debug) {
|
||
dbg.append("ECN enabled.\n");
|
||
}
|
||
}
|
||
|
||
for (RouteItem tri: routes) {
|
||
|
||
if (!tri.getDestlink().isUp()) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("linkdown.\n");
|
||
}
|
||
continue;
|
||
}
|
||
if (tri.getDestlink().isCongress(iPv6Packet,25.0)) {
|
||
if (debug) {
|
||
dbg.append(tri+"\n");
|
||
dbg.append("congress.\n");
|
||
}
|
||
//缓冲区留部分余量避免丢包
|
||
continue;
|
||
}
|
||
processPacket(iPv6Packet, tri,reroute);
|
||
return true;
|
||
}
|
||
//仍未成功发送,丢弃数据包
|
||
return false;
|
||
}
|
||
|
||
private void processPacket(IPv6Packet iPv6Packet, RouteItem ri, boolean reroute) throws IllegalRawDataException, IOException {
|
||
int hop = iPv6Packet.getHopLimit();
|
||
|
||
if (ri.getDestlink().isLoopBack()) {
|
||
IPv6SegmentRoutingHeader srhh =iPv6Packet. getSRHHeader();
|
||
if (srhh != null) {
|
||
processSRv6Packet(iPv6Packet, ri, srhh,reroute);
|
||
} else {
|
||
ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop());
|
||
}
|
||
} else {
|
||
if(iPv6Packet.getRerouteCounter().getAndIncrement()>=MAX_REROUTE_COUNT) {
|
||
|
||
//System.out.println("reroute count >=2");
|
||
return;
|
||
}
|
||
|
||
if(!reroute) {
|
||
// if(!iPv6Packet.isTTLdecreased()) {
|
||
hop--;
|
||
/* iPv6Packet.setTTLdecreased(true);
|
||
}else {
|
||
System.out.print("ttl err");
|
||
}*/
|
||
}
|
||
// 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.bufferAllocator.allocate(65535);
|
||
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, boolean reroute)
|
||
throws IllegalRawDataException, IOException {
|
||
|
||
if (srhh.getSegmentsLeft() <= 0) {
|
||
ri.getDestlink().sendPacket(iPv6Packet, ri.getNexthop());
|
||
} else {
|
||
if(reroute) {
|
||
|
||
}else {
|
||
int newSL = srhh.getSegmentsLeft() - 1;
|
||
srhh.setSegmentsLeft(newSL);
|
||
iPv6Packet.setDestinationAddress(srhh.getAddresses().get(newSL));
|
||
}
|
||
klalbRouteProtol.putHotspotAddress(iPv6Packet.getSourceAddress());
|
||
routePacket(iPv6Packet,reroute);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
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<>(256*2);
|
||
|
||
public Map<Integer, PacketConsumer> getProtocolNumberRegister() {
|
||
return protocolNumberRegister;
|
||
}
|
||
|
||
|
||
/*public void putProtocolNumberPacketAndInsertSRHAsync(IPv6Packet pkt) {
|
||
// inLoopBack.getReceiveConsumer().accept(pkt);
|
||
srhReceive.accept(pkt);
|
||
}
|
||
|
||
public void putProtocolNumberPacketAsync(IPv6Packet pkt) {
|
||
// inLoopBack.getReceiveConsumer().accept(pkt);
|
||
defaultReceive.accept(pkt);
|
||
}*/
|
||
}
|