forked from KNEMC/KLALB
KLALB V3.4
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.kne.cloud.network.klalb.KLALBRemoteLine;
|
||||
|
||||
public abstract class AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||
private CopyOnWriteArraySet<IPv6LinkStateListener> listeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
@Override
|
||||
public void addIPv6LinkStateListener(IPv6LinkStateListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener) {
|
||||
listeners.remove(listener);
|
||||
|
||||
}
|
||||
|
||||
public void onOnlineStateUpdate() {
|
||||
listeners.forEach((v) -> {
|
||||
v.onOnlineStateUpdate(this);
|
||||
});
|
||||
}
|
||||
public void onLocatorUpdate() {
|
||||
listeners.forEach((v) -> {
|
||||
v.onLocatorUpdate(this);
|
||||
});
|
||||
}
|
||||
|
||||
public void onAddressUpdate() {
|
||||
listeners.forEach((v) -> {
|
||||
v.onAddressUpdate(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||
import org.kne.io.KNEChannels;
|
||||
|
||||
public class ICMPv6EchoPacket extends ICMPv6Packet {
|
||||
private static final int ECHO_HEADER_LENGTH = 4; // 标识符(2) + 序列号(2)
|
||||
|
||||
public ICMPv6EchoPacket(boolean isRequest,int sequenceNumber,int identifier) {
|
||||
super(isRequest ? TYPE_ECHO_REQUEST : TYPE_ECHO_REPLY, 0);
|
||||
setSequenceNumber(sequenceNumber);
|
||||
setIdentifier(identifier);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取标识符
|
||||
*/
|
||||
public int getIdentifier() {
|
||||
return getHeader().getChar(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置标识符
|
||||
*/
|
||||
public void setIdentifier(int identifier) {
|
||||
getHeader().putChar(4, (char) identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取序列号
|
||||
*/
|
||||
public int getSequenceNumber() {
|
||||
return getHeader().getChar(6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置序列号
|
||||
*/
|
||||
public void setSequenceNumber(int sequenceNumber) {
|
||||
getHeader().putChar(6, (char) sequenceNumber);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建Ping请求包
|
||||
*/
|
||||
public static ICMPv6EchoPacket createPingRequest(int identifier, int sequenceNumber, byte[] payload) {
|
||||
ICMPv6EchoPacket packet = new ICMPv6EchoPacket(true,identifier,sequenceNumber);
|
||||
if (payload != null && payload.length > 0) {
|
||||
packet.getData().put(payload);
|
||||
packet.getData().flip();
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Ping回复包(基于请求包)
|
||||
*/
|
||||
public static ICMPv6EchoPacket createPingReply(ICMPv6EchoPacket request) {
|
||||
ICMPv6EchoPacket reply = new ICMPv6EchoPacket(false,request.getIdentifier(),request.getSequenceNumber());
|
||||
// 复制数据
|
||||
if (request.getData() != null && request.getData().limit() > 0) {
|
||||
ByteBuffer src = request.getData().duplicate();
|
||||
src.position(0);
|
||||
reply.getData().put(src);
|
||||
reply.getData().flip();
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String typeStr = getType() == TYPE_ECHO_REQUEST ? "Echo Request" : "Echo Reply";
|
||||
return String.format("ICMPv6 %s [ID:%d, Seq:%d, Data:%d bytes]",
|
||||
typeStr, getIdentifier(), getSequenceNumber(), getDataLength());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet.IPv6Payload;
|
||||
import org.kne.io.KNEChannels;
|
||||
|
||||
public class ICMPv6Packet extends IPv6Payload {
|
||||
public static final int ICMPv6_PROTOCOL_NUMBER = 58;
|
||||
public static final int ICMPv6_HEADER_LENGTH = 8; // ICMPv6基础头部固定8字节
|
||||
|
||||
// ICMPv6类型常量
|
||||
public static final int TYPE_DESTINATION_UNREACHABLE = 1;
|
||||
public static final int TYPE_PACKET_TOO_BIG = 2;
|
||||
public static final int TYPE_TIME_EXCEEDED = 3;
|
||||
public static final int TYPE_PARAMETER_PROBLEM = 4;
|
||||
public static final int TYPE_ECHO_REQUEST = 128;
|
||||
public static final int TYPE_ECHO_REPLY = 129;
|
||||
|
||||
private ByteBuffer header = NetworkPacket.bufferAllocator.allocate(ICMPv6_HEADER_LENGTH);
|
||||
private ByteBuffer data;
|
||||
|
||||
public ICMPv6Packet() {
|
||||
super(ICMPv6_PROTOCOL_NUMBER, false);
|
||||
}
|
||||
|
||||
public ICMPv6Packet(int type, int code) {
|
||||
super(ICMPv6_PROTOCOL_NUMBER, false);
|
||||
getHeader().put((byte) type);
|
||||
getHeader().put((byte) code);
|
||||
// 校验和字段初始为0,后续计算
|
||||
getHeader().putChar((char) 0);
|
||||
data = NetworkPacket.bufferAllocator.allocate(65535);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalLength() {
|
||||
return data != null ? data.limit() + ICMPv6_HEADER_LENGTH : ICMPv6_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||
// 写入头部和数据
|
||||
dto.write(getHeader().slice(0, ICMPv6_HEADER_LENGTH));
|
||||
if (data != null && data.limit() > 0) {
|
||||
dto.write(data.slice(0, data.limit()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
||||
// 读取ICMPv6头部
|
||||
getHeader().clear().limit(ICMPv6_HEADER_LENGTH);
|
||||
KNEChannels.readFully(din, getHeader());
|
||||
|
||||
// 读取数据部分(总长度减去头部长度)
|
||||
long dataLength = length - ICMPv6_HEADER_LENGTH;
|
||||
|
||||
if (dataLength < 0) {
|
||||
throw new IOException("Invalid ICMPv6 packet: total length < header length");
|
||||
}
|
||||
|
||||
if (dataLength > 0) {
|
||||
data = NetworkPacket.bufferAllocator.allocate((int) dataLength);
|
||||
KNEChannels.readFully(din, data);
|
||||
data.flip();
|
||||
} else {
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean needEndPosition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ICMPv6类型
|
||||
*/
|
||||
public int getType() {
|
||||
return getHeader().get(0) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ICMPv6类型
|
||||
*/
|
||||
public void setType(int type) {
|
||||
getHeader().put(0, (byte) type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ICMPv6代码
|
||||
*/
|
||||
public int getCode() {
|
||||
return getHeader().get(1) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置ICMPv6代码
|
||||
*/
|
||||
public void setCode(int code) {
|
||||
getHeader().put(1, (byte) code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取校验和
|
||||
*/
|
||||
public int getChecksum() {
|
||||
return getHeader().getChar(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置校验和
|
||||
*/
|
||||
public void setChecksum(int checksum) {
|
||||
getHeader().putChar(2, (char) checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息体(不同类型ICMPv6消息的特定字段)
|
||||
* 对于Echo请求/回复,这是标识符和序列号
|
||||
* 对于错误消息,这是未使用的字段和原始数据包片段
|
||||
*/
|
||||
public int getMessageBody() {
|
||||
return getHeader().getInt(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置消息体
|
||||
*/
|
||||
public void setMessageBody(int messageBody) {
|
||||
getHeader().putInt(4, messageBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据部分长度
|
||||
*/
|
||||
public int getDataLength() {
|
||||
return data != null ? data.limit() : 0;
|
||||
}
|
||||
|
||||
public ByteBuffer getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算ICMPv6校验和
|
||||
* ICMPv6校验和计算包括IPv6伪首部和整个ICMPv6报文
|
||||
*/
|
||||
public int calculateChecksum() {
|
||||
if (getParent() == null) {
|
||||
throw new IllegalStateException("Parent IPv6 packet required for checksum calculation");
|
||||
}
|
||||
|
||||
// 保存原始校验和值
|
||||
int originalChecksum = getChecksum();
|
||||
|
||||
try {
|
||||
// 临时将校验和字段设为0
|
||||
setChecksum(0);
|
||||
|
||||
long sum = 0;
|
||||
|
||||
// IPv6伪首部
|
||||
byte[] srcAddr = new byte[16], dstAddr = new byte[16];
|
||||
getParent().getRawSourceAddress(srcAddr);
|
||||
getParent().getRawDestinationAddress(dstAddr);
|
||||
|
||||
for (int i = 0; i < 16; i += 2) {
|
||||
sum += ((srcAddr[i] & 0xFF) << 8) | (srcAddr[i + 1] & 0xFF);
|
||||
sum += ((dstAddr[i] & 0xFF) << 8) | (dstAddr[i + 1] & 0xFF);
|
||||
}
|
||||
|
||||
// ICMPv6报文长度
|
||||
int totalLength = (int) getTotalLength();
|
||||
sum += (totalLength >>> 16) + totalLength;
|
||||
sum += ICMPv6_PROTOCOL_NUMBER;
|
||||
|
||||
// ICMPv6头部
|
||||
ByteBuffer headerCopy = getHeader().duplicate();
|
||||
headerCopy.position(0).limit(ICMPv6_HEADER_LENGTH);
|
||||
while (headerCopy.remaining() >= 2) {
|
||||
sum += headerCopy.getChar();
|
||||
}
|
||||
|
||||
// ICMPv6数据
|
||||
if (data != null && data.limit() > 0) {
|
||||
ByteBuffer dataCopy = data.duplicate();
|
||||
dataCopy.position(0);
|
||||
|
||||
while (dataCopy.remaining() >= 2) {
|
||||
sum += dataCopy.getChar();
|
||||
}
|
||||
|
||||
if (dataCopy.remaining() == 1) {
|
||||
sum += (dataCopy.get() & 0xFF) << 8;
|
||||
}
|
||||
}
|
||||
|
||||
// 折叠进位并取反
|
||||
while ((sum >> 16) != 0) {
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
}
|
||||
|
||||
int checksum = (int) (~sum & 0xFFFF);
|
||||
return checksum == 0 ? 0xFFFF : checksum;
|
||||
|
||||
} finally {
|
||||
// 恢复原始校验和值
|
||||
setChecksum(originalChecksum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新校验和
|
||||
*/
|
||||
public void updateChecksum() {
|
||||
setChecksum(calculateChecksum());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证校验和
|
||||
*/
|
||||
public boolean verifyChecksum() {
|
||||
int storedChecksum = getChecksum();
|
||||
return storedChecksum == 0 || storedChecksum == calculateChecksum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("ICMPv6 Type:").append(getType())
|
||||
.append(" Code:").append(getCode())
|
||||
.append(" [Total:").append(getTotalLength())
|
||||
.append(", Data:").append(getDataLength()).append("]");
|
||||
|
||||
if (data != null && data.limit() > 0) {
|
||||
byte[] b = new byte[Math.min(data.limit(), 10)];
|
||||
data.get(0, b);
|
||||
sb.append(" ").append(Arrays.toString(b));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
// 测试方法
|
||||
public static void main(String[] args) {
|
||||
// 创建一个Echo Request类型的ICMPv6包
|
||||
ICMPv6Packet icmpv6 = new ICMPv6Packet(TYPE_ECHO_REQUEST, 0);
|
||||
icmpv6.setMessageBody(0x12345678); // 设置标识符和序列号
|
||||
|
||||
// 添加一些测试数据
|
||||
ByteBuffer testData = NetworkPacket.bufferAllocator.allocate(4);
|
||||
testData.put("test".getBytes());
|
||||
testData.flip();
|
||||
icmpv6.data = testData;
|
||||
|
||||
// 创建父IPv6包(用于校验和计算)
|
||||
IPv6Packet ipv6 = new IPv6Packet();
|
||||
// 这里需要设置源和目的地址,但为了示例简化
|
||||
|
||||
icmpv6.setParent(ipv6);
|
||||
|
||||
System.out.println("Original checksum: " + icmpv6.calculateChecksum());
|
||||
icmpv6.setChecksum(1);
|
||||
System.out.println("Checksum verification (should be false): " + icmpv6.verifyChecksum());
|
||||
icmpv6.updateChecksum();
|
||||
System.out.println("Checksum verification (should be true): " + icmpv6.verifyChecksum());
|
||||
System.out.println(icmpv6);
|
||||
}
|
||||
|
||||
public ByteBuffer getHeader() {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
import org.kne.io.KNEChannels;
|
||||
|
||||
public class ICMPv6TimeExceededPacket extends ICMPv6Packet {
|
||||
private static final int UNUSED_FIELD_LENGTH = 4; // 未使用字段长度
|
||||
|
||||
// 代码值常量
|
||||
public static final int CODE_HOP_LIMIT_EXCEEDED = 0; // 跳数限制超时
|
||||
public static final int CODE_FRAGMENT_REASSEMBLY_EXCEEDED = 1; // 分片重组超时
|
||||
|
||||
public ICMPv6TimeExceededPacket(int code) {
|
||||
super(TYPE_TIME_EXCEEDED, code);
|
||||
setUnused(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未使用字段(通常为0)
|
||||
*/
|
||||
public int getUnused() {
|
||||
return getHeader().getInt(4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置未使用字段(通常设为0)
|
||||
*/
|
||||
public void setUnused(int unused) {
|
||||
getHeader().putInt(4, unused);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建跳数限制超时包
|
||||
*/
|
||||
public static ICMPv6TimeExceededPacket createHopLimitExceeded(IPv6Packet originalPacket) {
|
||||
ICMPv6TimeExceededPacket packet = new ICMPv6TimeExceededPacket(CODE_HOP_LIMIT_EXCEEDED);
|
||||
|
||||
// 包含原始数据包的前缀(根据RFC,尽可能包含但不超出最小MTU)
|
||||
if (originalPacket == null) {
|
||||
throw new NullPointerException("originalPacket is null!");
|
||||
}
|
||||
// 这里简化处理,实际应该序列化原始包的前1280字节(IPv6最小MTU)
|
||||
ByteBuffer buffer = NetworkPacket.bufferAllocator.allocate(65536);
|
||||
buffer.clear();
|
||||
try {
|
||||
originalPacket.writeToChannel(KNEChannels.newWritableChannel(buffer));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
buffer.flip();
|
||||
buffer.limit(Math.min(1280, buffer.limit()));
|
||||
packet.getData().clear();
|
||||
packet.getData().put(buffer);
|
||||
packet.getData().flip();
|
||||
return packet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String codeStr = getCode() == CODE_HOP_LIMIT_EXCEEDED ?
|
||||
"Hop Limit Exceeded" : "Fragment Reassembly Time Exceeded";
|
||||
return String.format("ICMPv6 Time Exceeded [%s, OriginalPrefix:%d bytes]",
|
||||
codeStr, getDataLength());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.kne.cloud.network.NetworkPacket;
|
||||
|
||||
public class IPv6HopByHopTLV extends TLV {
|
||||
public static final int PAD1 = 0;
|
||||
public static final int PADN = 1;
|
||||
public static final int JUMBO_PAYLOAD = 0xC2;
|
||||
public static final int ROUTER_ALERT = 0x05;
|
||||
|
||||
public IPv6HopByHopTLV(ByteBuffer header) {
|
||||
this(header, true);
|
||||
}
|
||||
|
||||
public IPv6HopByHopTLV(ByteBuffer header, boolean isDefault) {
|
||||
super(header, isDefault);
|
||||
}
|
||||
|
||||
public IPv6HopByHopTLV(int type) {
|
||||
this(type, true);
|
||||
}
|
||||
|
||||
public IPv6HopByHopTLV(int type, boolean isDefault) {
|
||||
super(type, isDefault);
|
||||
}
|
||||
|
||||
public static IPv6HopByHopTLV readIPv6HopByHopTLVFromChannel(ReadableByteChannel din) throws IOException {
|
||||
ByteBuffer bbf = NetworkPacket.bufferAllocator.allocate(2);
|
||||
bbf.limit(1);
|
||||
while (bbf.hasRemaining()) {
|
||||
if (din.read(bbf) == -1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
int type = bbf.get(0) & 0xff;
|
||||
IPv6HopByHopTLV htlv;
|
||||
|
||||
switch(type) {
|
||||
case PAD1:
|
||||
// Pad1: 只有类型字段,没有数据部分
|
||||
htlv = new Pad1HopByHopTLV(bbf);
|
||||
htlv.readFromChannel(din, 0);
|
||||
return htlv;
|
||||
case PADN:
|
||||
// PadN: 有数据部分
|
||||
htlv = new PadNHopByHopTLV(bbf);
|
||||
htlv.readFromChannel(din, 0);
|
||||
return htlv;
|
||||
case ROUTER_ALERT:
|
||||
// 路由器告警: 有数据部分
|
||||
htlv = new RouterAlertHopByHopTLV(bbf, true);
|
||||
htlv.readFromChannel(din, 0);
|
||||
return htlv;
|
||||
case JUMBO_PAYLOAD:
|
||||
// 巨型载荷: 有数据部分
|
||||
htlv = new JumboPayloadHopByHopTLV(bbf, true);
|
||||
htlv.readFromChannel(din, 0);
|
||||
return htlv;
|
||||
default:
|
||||
// 未知类型: 假设有数据部分
|
||||
htlv = new IPv6HopByHopTLV(bbf, true);
|
||||
htlv.readFromChannel(din, 0);
|
||||
return htlv;
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeIPv6HopByHopTLVToChannel(WritableByteChannel dto, IPv6HopByHopTLV tlv) throws IOException {
|
||||
tlv.writeToChannel(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IPv6HopByHopTLV [getType()=" + getType() + ", getDataLength()=" + getDataLength() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 路由器告警 TLV - 有数据部分
|
||||
*/
|
||||
class RouterAlertHopByHopTLV extends IPv6HopByHopTLV {
|
||||
public RouterAlertHopByHopTLV(ByteBuffer header, boolean isDefault) {
|
||||
super(header, isDefault); // isDefault = true: 有数据部分
|
||||
}
|
||||
|
||||
public short getAlertValue() {
|
||||
if (getData() != null && getData().remaining() >= 2) {
|
||||
ByteBuffer duplicate = getData().duplicate();
|
||||
return duplicate.getShort();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setAlertValue(short value) {
|
||||
if (getData() == null) {
|
||||
// 根据isDefault逻辑,可能需要分配数据缓冲区
|
||||
// 这里简化处理
|
||||
return;
|
||||
}
|
||||
ByteBuffer duplicate = getData().duplicate();
|
||||
duplicate.putShort(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 巨型载荷 TLV - 有数据部分
|
||||
*/
|
||||
class JumboPayloadHopByHopTLV extends IPv6HopByHopTLV {
|
||||
public JumboPayloadHopByHopTLV(ByteBuffer header, boolean isDefault) {
|
||||
super(header, isDefault); // isDefault = true: 有数据部分
|
||||
}
|
||||
|
||||
public int getJumboLength() {
|
||||
if (getData() != null && getData().remaining() >= 4) {
|
||||
ByteBuffer duplicate = getData().duplicate();
|
||||
return duplicate.getInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setJumboLength(int length) {
|
||||
if (getData() == null) return;
|
||||
ByteBuffer duplicate = getData().duplicate();
|
||||
duplicate.putInt(length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public interface IPv6LinkStateListener {
|
||||
public void onOnlineStateUpdate(IPv6NetworkLink link);
|
||||
public void onAddressUpdate(IPv6NetworkLink link);
|
||||
public void onLocatorUpdate(IPv6NetworkLink link);
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package org.kne.cloud.network.ipv6;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.kne.cloud.network.ipv6.IPv6Packet;
|
||||
@@ -12,7 +14,7 @@ import org.kne.cloud.network.monitor.SpeedAndTrafficAndDelayMonitorDataImpl;
|
||||
|
||||
public interface IPv6NetworkLink {
|
||||
public boolean isLoopBack();
|
||||
public Inet6AddressGroup getAddressGroup();
|
||||
public List<Inet6AddressGroup> getAddressGroups();
|
||||
public List<Neighbor> getNeighborsInfo();
|
||||
public List<RouteItem> getRouteItems();
|
||||
public void sendPacket(IPv6Packet pack, Inet6Address inet6Address) throws IOException;
|
||||
@@ -22,8 +24,10 @@ public interface IPv6NetworkLink {
|
||||
}
|
||||
public String getName();
|
||||
public boolean isUp();
|
||||
public boolean canSend(IPv6Packet iPv6Packet);
|
||||
public void setReceiveConsumer(Consumer<IPv6Packet>con);
|
||||
void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer);
|
||||
public boolean isReachSpeedLimit(IPv6Packet iPv6Packet);
|
||||
public void setCongressCondition(Lock lock,Condition condition);
|
||||
public void addIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||
public void removeIPv6LinkStateListener(IPv6LinkStateListener listener);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,305 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.util.Objects;
|
||||
|
||||
public class IPv6RouteTableKey {
|
||||
private long most;
|
||||
private long least;
|
||||
|
||||
public IPv6RouteTableKey(byte[] address) {
|
||||
long[] l = inet6AddressToLongs(address);
|
||||
this.most = l[0];
|
||||
this.least = l[1]; // 修复:应该是 l[1] 而不是 l[0]
|
||||
}
|
||||
|
||||
public IPv6RouteTableKey(long most, long least) {
|
||||
super();
|
||||
this.most = most;
|
||||
this.least = least;
|
||||
}
|
||||
|
||||
public IPv6RouteTableKey(Inet6Address address) {
|
||||
this(address.getAddress());
|
||||
}
|
||||
|
||||
public IPv6RouteTableKey(Inet6AddressGroup address) {
|
||||
this(address.getAddress());
|
||||
applyMask(address.getPrefixLength());
|
||||
}
|
||||
|
||||
public long getMost() {
|
||||
return most;
|
||||
}
|
||||
|
||||
public long getLeast() {
|
||||
return least;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (int) (least ^ (least >>> 32));
|
||||
result = prime * result + (int) (most ^ (most >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
IPv6RouteTableKey other = (IPv6RouteTableKey) obj;
|
||||
if (least != other.least)
|
||||
return false;
|
||||
if (most != other.most)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据前缀长度应用掩码,仅保留网络部分
|
||||
* @param prefixLength 前缀长度 (0-128)
|
||||
* @return 应用掩码后的新 IPv6RouteTableKey 对象
|
||||
*/
|
||||
public IPv6RouteTableKey mask(int prefixLength) {
|
||||
if (prefixLength < 0 || prefixLength > 128) {
|
||||
throw new IllegalArgumentException("前缀长度必须在 0 到 128 之间");
|
||||
}
|
||||
|
||||
if (prefixLength == 0) {
|
||||
return new IPv6RouteTableKey(0L, 0L); // 默认路由
|
||||
}
|
||||
|
||||
long maskedMost = this.most;
|
||||
long maskedLeast = this.least;
|
||||
|
||||
if (prefixLength <= 64) {
|
||||
// 仅影响高位
|
||||
long mask = createMask(prefixLength);
|
||||
maskedMost &= mask;
|
||||
maskedLeast = 0L; // 低位全部清零
|
||||
} else {
|
||||
// 影响高位和部分低位
|
||||
int lowPrefixLength = prefixLength - 64;
|
||||
long lowMask = createMask(lowPrefixLength);
|
||||
maskedLeast &= lowMask;
|
||||
// 高位保持不变
|
||||
}
|
||||
|
||||
return new IPv6RouteTableKey(maskedMost, maskedLeast);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据前缀长度应用掩码,仅保留网络部分
|
||||
* @param prefixLength 前缀长度 (0-128)
|
||||
* @return 应用掩码后的新 IPv6RouteTableKey 对象
|
||||
*/
|
||||
public void applyMask(int prefixLength) {
|
||||
if (prefixLength < 0 || prefixLength > 128) {
|
||||
throw new IllegalArgumentException("前缀长度必须在 0 到 128 之间");
|
||||
}
|
||||
|
||||
if (prefixLength == 0) {
|
||||
this.most=0;
|
||||
this.least=0;
|
||||
return;
|
||||
//return new IPv6RouteTableKey(0L, 0L); // 默认路由
|
||||
}
|
||||
|
||||
long maskedMost = this.most;
|
||||
long maskedLeast = this.least;
|
||||
|
||||
if (prefixLength <= 64) {
|
||||
// 仅影响高位
|
||||
long mask = createMask(prefixLength);
|
||||
maskedMost &= mask;
|
||||
maskedLeast = 0L; // 低位全部清零
|
||||
} else {
|
||||
// 影响高位和部分低位
|
||||
int lowPrefixLength = prefixLength - 64;
|
||||
long lowMask = createMask(lowPrefixLength);
|
||||
maskedLeast &= lowMask;
|
||||
// 高位保持不变
|
||||
}
|
||||
this.most=maskedMost;
|
||||
this.least=maskedLeast;
|
||||
// return new IPv6RouteTableKey(maskedMost, maskedLeast);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定长度的掩码
|
||||
* @param bits 要保留的位数 (0-64)
|
||||
* @return 掩码值
|
||||
*/
|
||||
private long createMask(int bits) {
|
||||
// 使用查表法,预先计算所有可能的掩码值
|
||||
return MASK_TABLE[bits];
|
||||
}
|
||||
|
||||
// 预计算的掩码表
|
||||
private static final long[] MASK_TABLE = new long[65]; // 0-64 共65个值
|
||||
|
||||
// 静态初始化块,在类加载时预计算所有掩码值
|
||||
static {
|
||||
for (int bits = 0; bits <= 64; bits++) {
|
||||
if (bits == 0) {
|
||||
MASK_TABLE[bits] = 0L;
|
||||
} else if (bits == 64) {
|
||||
MASK_TABLE[bits] = -1L;
|
||||
} else {
|
||||
MASK_TABLE[bits] = (-1L) << (64 - bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 byte[] 转换为两个 long 值(高位和低位)
|
||||
* @param bytes 16字节的IPv6地址
|
||||
* @return 包含两个long值的数组,第一个是高位,第二个是低位
|
||||
*/
|
||||
public static long[] inet6AddressToLongs(byte[] bytes) {
|
||||
if (bytes.length != 16) {
|
||||
throw new IllegalArgumentException("IPv6地址必须是16字节");
|
||||
}
|
||||
|
||||
long high = 0;
|
||||
long low = 0;
|
||||
|
||||
// 处理前8字节(高位)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
high = (high << 8) | (bytes[i] & 0xFF);
|
||||
}
|
||||
|
||||
// 处理后8字节(低位)
|
||||
for (int i = 8; i < 16; i++) {
|
||||
low = (low << 8) | (bytes[i] & 0xFF);
|
||||
}
|
||||
|
||||
return new long[]{high, low};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将两个long值转换回byte[]
|
||||
* @param high 高位long值
|
||||
* @param low 低位long值
|
||||
* @return 16字节的IPv6地址
|
||||
*/
|
||||
public static byte[] longsToInet6Address(long high, long low) {
|
||||
byte[] bytes = new byte[16];
|
||||
|
||||
// 提取高位的8个字节
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bytes[i] = (byte) ((high >> (56 - i * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
// 提取低位的8个字节
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bytes[8 + i] = (byte) ((low >> (56 - i * 8)) & 0xFF);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%016x:%016x", most, least);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单元测试
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
for(int i=0;i<65;i++) {
|
||||
long l=MASK_TABLE[i];
|
||||
System.out.println(Long.toUnsignedString(l, 16));
|
||||
}
|
||||
|
||||
System.out.println("开始 IPv6RouteTableKey 单元测试...");
|
||||
|
||||
// 测试1: 基本转换测试
|
||||
System.out.println("\n1. 测试基本转换:");
|
||||
byte[] testAddress = new byte[16];
|
||||
// 创建测试地址: 2001:0db8:85a3::8a2e:0370:7334
|
||||
testAddress[0] = 0x20; testAddress[1] = 0x01;
|
||||
testAddress[2] = 0x0d; testAddress[3] = (byte) 0xb8;
|
||||
testAddress[4] = (byte) 0x85; testAddress[5] = (byte) 0xa3;
|
||||
// 中间部分为0
|
||||
testAddress[12] = (byte) 0x8a; testAddress[13] = 0x2e;
|
||||
testAddress[14] = 0x03; testAddress[15] = 0x70;
|
||||
// testAddress[16] = 0x73; testAddress[17] = 0x34; // 注意: 数组只有16个元素
|
||||
|
||||
IPv6RouteTableKey key = new IPv6RouteTableKey(testAddress);
|
||||
System.out.println("原始地址: " + key);
|
||||
|
||||
// 测试2: 掩码应用测试
|
||||
System.out.println("\n2. 测试掩码应用:");
|
||||
IPv6RouteTableKey masked64 = key.mask(64);
|
||||
System.out.println("/64 掩码: " + masked64);
|
||||
|
||||
IPv6RouteTableKey masked48 = key.mask(48);
|
||||
System.out.println("/48 掩码: " + masked48);
|
||||
|
||||
IPv6RouteTableKey masked128 = key.mask(128);
|
||||
System.out.println("/128 掩码: " + masked128);
|
||||
|
||||
IPv6RouteTableKey masked0 = key.mask(0);
|
||||
System.out.println("/0 掩码: " + masked0);
|
||||
|
||||
// 测试3: 相等性测试
|
||||
System.out.println("\n3. 测试相等性:");
|
||||
IPv6RouteTableKey key2 = new IPv6RouteTableKey(testAddress);
|
||||
System.out.println("相同地址是否相等: " + key.equals(key2));
|
||||
System.out.println("哈希码是否相同: " + (key.hashCode() == key2.hashCode()));
|
||||
|
||||
// 测试4: 转换函数测试
|
||||
System.out.println("\n4. 测试转换函数:");
|
||||
long[] longs = inet6AddressToLongs(testAddress);
|
||||
System.out.println("转换为longs: " + Long.toHexString(longs[0]) + ":" + Long.toHexString(longs[1]));
|
||||
|
||||
byte[] reconverted = longsToInet6Address(longs[0], longs[1]);
|
||||
boolean conversionOk = true;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (testAddress[i] != reconverted[i]) {
|
||||
conversionOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println("转换是否可逆: " + conversionOk);
|
||||
|
||||
// 测试5: 边界条件测试
|
||||
System.out.println("\n5. 测试边界条件:");
|
||||
try {
|
||||
key.applyMask(-1);
|
||||
System.out.println("错误: 应该抛出异常");
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.out.println("正确: 负前缀长度抛出异常");
|
||||
}
|
||||
|
||||
try {
|
||||
key.applyMask(129);
|
||||
System.out.println("错误: 应该抛出异常");
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.out.println("正确: 过大前缀长度抛出异常");
|
||||
}
|
||||
|
||||
// 测试6: 全零和全一地址测试
|
||||
System.out.println("\n6. 测试特殊地址:");
|
||||
byte[] allZeros = new byte[16];
|
||||
IPv6RouteTableKey zeroKey = new IPv6RouteTableKey(allZeros);
|
||||
System.out.println("全零地址: " + zeroKey);
|
||||
|
||||
byte[] allOnes = new byte[16];
|
||||
for (int i = 0; i < 16; i++) allOnes[i] = (byte) 0xFF;
|
||||
IPv6RouteTableKey onesKey = new IPv6RouteTableKey(allOnes);
|
||||
System.out.println("全一地址: " + onesKey);
|
||||
|
||||
System.out.println("\n所有测试完成!");
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,12 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -40,7 +42,7 @@ import org.kne.concurrent.HighPerformanceExecutor;
|
||||
import org.kne.concurrent.SpinLock;
|
||||
import org.kne.io.KNEChannels;
|
||||
|
||||
public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, AutoCloseable {
|
||||
public class IPv6TUNLoopbackNetworkLink extends AbstractIPv6NetworkLink implements IPv6NetworkLink, Closeable, AutoCloseable {
|
||||
|
||||
public static final String KLALB_DECENTRALIZED_S_RV6_NETWORK = "KLALB Decentralized SRv6 Network";
|
||||
|
||||
@@ -76,7 +78,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
}
|
||||
Thread tb = new Thread(() -> {
|
||||
while (true) {
|
||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocateNative(65535);
|
||||
try {
|
||||
tun.read(tmp);
|
||||
tmp.flip();
|
||||
@@ -91,8 +93,8 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
//NetworkPacket.databufferpool_65535.back(tmp);
|
||||
if (con != null) {
|
||||
|
||||
monitor.getOutPacketCounterAL().incrementAndGet();
|
||||
monitor.getOutTrafficAL().addAndGet(ipp.getLength());
|
||||
monitor.getOutPacketCounterAL().add(1);
|
||||
monitor.getOutTrafficAL().add(ipp.getTotalLength());
|
||||
// ipp.setDisposeAfterSend(true);
|
||||
// ipp.getPayload().setDisposeAfterSend(true);
|
||||
ipp.setPromise(true);
|
||||
@@ -152,6 +154,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
}catch(UnsatisfiedLinkError e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
onOnlineStateUpdate();
|
||||
}
|
||||
|
||||
private LinkedBlockingQueue<ByteBuffer> sendQueue = new LinkedBlockingQueue<ByteBuffer>();
|
||||
@@ -210,14 +213,15 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
SRv6PacketReorder newr= new SRv6PacketReorder(new PacketConsumer() {
|
||||
|
||||
@Override
|
||||
public void accept(IPv6Packet packx) throws IOException {
|
||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
||||
public boolean accept(IPv6Packet packx) throws IOException {
|
||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocateNative(65535);
|
||||
packx.writeToChannel(KNEChannels.newWritableChannel(tmp));
|
||||
monitor.getInPacketCounterAL().incrementAndGet();
|
||||
monitor.getInTrafficAL().addAndGet(packx.getLength());
|
||||
monitor.getInPacketCounterAL().add(1);
|
||||
monitor.getInTrafficAL().add(packx.getTotalLength());
|
||||
tmp.flip();
|
||||
sendQueue.add(tmp);
|
||||
LockSupport.unpark(tr);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
SRv6PacketReorder olr=reorder.putIfAbsent(fss,newr);
|
||||
@@ -230,8 +234,8 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
}else {
|
||||
ByteBuffer tmp = NetworkPacket.bufferAllocator.allocate(65535);
|
||||
pack.writeToChannel(KNEChannels.newWritableChannel(tmp));
|
||||
monitor.getInPacketCounterAL().incrementAndGet();
|
||||
monitor.getInTrafficAL().addAndGet(pack.getLength());
|
||||
monitor.getInPacketCounterAL().add(1);
|
||||
monitor.getInTrafficAL().add(pack.getTotalLength());
|
||||
tmp.flip();
|
||||
sendQueue.add(tmp);
|
||||
LockSupport.unpark(tr);
|
||||
@@ -282,11 +286,7 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
tun.close();
|
||||
tun = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSend(IPv6Packet iPv6Packet) {
|
||||
return true;
|
||||
onOnlineStateUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -303,8 +303,8 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inet6AddressGroup getAddressGroup() {
|
||||
return hostAddress;
|
||||
public List< Inet6AddressGroup> getAddressGroups() {
|
||||
return List.of(hostAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -316,8 +316,10 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
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, 1, null, "D",true));
|
||||
for(Inet6AddressGroup grp:getAddressGroups()) {
|
||||
rlist.add(new RouteItem(new Inet6AddressGroup(grp.getAddress(), 128),
|
||||
grp.getAddress(), this, "Direct", 0, 1, null, "D",true));
|
||||
}
|
||||
|
||||
for (Iterator<Neighbor> iteratorx = getNeighborsInfo()
|
||||
.iterator(); iteratorx.hasNext();) {
|
||||
@@ -339,4 +341,11 @@ public class IPv6TUNLoopbackNetworkLink implements IPv6NetworkLink, Closeable, A
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCongressCondition(Lock lock, Condition condition) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Inet6AddressGroup implements Comparable<Inet6AddressGroup>{
|
||||
private static final byte[][] maskTransf=new byte[129][16];
|
||||
@@ -121,4 +122,21 @@ public class Inet6AddressGroup implements Comparable<Inet6AddressGroup>{
|
||||
prefixLength=in.read();
|
||||
}
|
||||
|
||||
public Inet6AddressGroup createPrefixOnlyAddressGroup(int newPrefixLength) {
|
||||
byte[]mask=maskTransf[newPrefixLength];
|
||||
byte[]andm=getAndm(mask);
|
||||
try {
|
||||
return new Inet6AddressGroup((Inet6Address) Inet6Address.getByAddress(andm), newPrefixLength);
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public Inet6AddressGroup createPrefixOnlyAddressGroup() {
|
||||
return createPrefixOnlyAddressGroup(prefixLength);
|
||||
}
|
||||
public static void main(String[] args) throws UnknownHostException {
|
||||
Inet6AddressGroup i6ag=new Inet6AddressGroup((Inet6Address) Inet6Address.getByName("1234:1234::1234"),12);
|
||||
System.out.println(i6ag);
|
||||
System.out.println(i6ag.createPrefixOnlyAddressGroup());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.kne.cloud.network.srv6.PacketConsumer;
|
||||
import org.kne.cloud.network.srv6.SRv6Router;
|
||||
|
||||
public class LoopbackIPv6NetworkLink extends AbstractIPv6NetworkLink implements IPv6NetworkLink {
|
||||
private IPv6NetworkLink fallbackLink;
|
||||
|
||||
|
||||
public IPv6NetworkLink getFallbackLink() {
|
||||
return fallbackLink;
|
||||
}
|
||||
|
||||
public void setFallbackLink(IPv6NetworkLink fallbackLink) {
|
||||
this.fallbackLink = fallbackLink;
|
||||
}
|
||||
|
||||
private Map<Integer, PacketConsumer> protocolNumberRegister = new ConcurrentHashMap<>(256 * 2);
|
||||
|
||||
public Map<Integer, PacketConsumer> getProtocolNumberRegister() {
|
||||
return protocolNumberRegister;
|
||||
}
|
||||
|
||||
private List<Inet6AddressGroup> addressGroups =new ArrayList<>();
|
||||
|
||||
//new Inet6AddressGroup(loopbackAddress, 128) new Inet6AddressGroup((Inet6Address) Inet6Address.getByName("::1"), 128)
|
||||
public LoopbackIPv6NetworkLink(List<Inet6AddressGroup> addressGroupsx,SRv6Router router) {
|
||||
this.addressGroups .addAll( addressGroupsx);
|
||||
}
|
||||
|
||||
public Consumer<IPv6Packet> getReceiveConsumer() {
|
||||
return receiveConsumer;
|
||||
}
|
||||
|
||||
private Consumer<IPv6Packet> receiveConsumer;
|
||||
private Consumer<IPv6Packet> rerouteConsumer;
|
||||
private SRv6Router router;
|
||||
|
||||
@Override
|
||||
public void sendPacket(IPv6Packet pack, Inet6Address next) throws IOException {
|
||||
PacketConsumer pcm= protocolNumberRegister.get(pack.getPayload().getProtocolNumber());
|
||||
if (pcm != null) {
|
||||
if(!pcm.accept(pack)) {
|
||||
if(fallbackLink!=null) {
|
||||
fallbackLink.sendPacket(pack, next);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if(fallbackLink!=null) {
|
||||
fallbackLink.sendPacket(pack, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 void setReceiveConsumer(Consumer<IPv6Packet> con) {
|
||||
this.receiveConsumer = con;
|
||||
if(fallbackLink!=null) {
|
||||
fallbackLink.setReceiveConsumer(con);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Inet6AddressGroup> getAddressGroups() {
|
||||
return addressGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRerouteConsumer(Consumer<IPv6Packet> rerouteConsumer) {
|
||||
this.rerouteConsumer=rerouteConsumer;
|
||||
if(fallbackLink!=null) {
|
||||
fallbackLink.setRerouteConsumer(rerouteConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
public Consumer<IPv6Packet> getRerouteConsumer() {
|
||||
return rerouteConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RouteItem> getRouteItems() {
|
||||
List<RouteItem> rlist = new ArrayList<>();
|
||||
for(Inet6AddressGroup group:addressGroups) {
|
||||
rlist.add(new RouteItem(new Inet6AddressGroup(group.getAddress(), 128),
|
||||
group.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 SRv6Router getRouter() {
|
||||
return router;
|
||||
}
|
||||
|
||||
public void setRouter(SRv6Router router) {
|
||||
this.router = router;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCongressCondition(Lock lock, Condition condition) {
|
||||
// TODO 自动生成的方法存根
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
@@ -32,9 +32,9 @@ public class Neighbor {
|
||||
this.locator = locator;
|
||||
this.monitor = monitor;
|
||||
}
|
||||
public Neighbor(Inet6AddressGroup peerAddress, Inet6AddressGroup remoteVaddr, QueueingMonitorDataImpl monitor2,
|
||||
public Neighbor(Inet6AddressGroup address, Inet6AddressGroup locator, MonitorData monitor2,
|
||||
BandwidthDistributer<Inet6Address> bandwidthDistributer) {
|
||||
this(peerAddress,remoteVaddr,monitor2);
|
||||
this(address,locator,monitor2);
|
||||
this.bandwidthDistributer=bandwidthDistributer;
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.kne.cloud.network.srv6.IPv6SegmentRoutingTLV;
|
||||
|
||||
/**
|
||||
* Pad1 Hop-by-Hop TLV - 没有数据部分
|
||||
*/
|
||||
public class Pad1HopByHopTLV extends IPv6HopByHopTLV {
|
||||
public Pad1HopByHopTLV() {
|
||||
super(IPv6HopByHopTLV.PAD1);
|
||||
}
|
||||
|
||||
public Pad1HopByHopTLV(ByteBuffer klalbHeader) {
|
||||
super(klalbHeader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pad1HopByHopTLV []";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.kne.cloud.network.ipv6;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.kne.cloud.network.srv6.IPv6SegmentRoutingTLV;
|
||||
|
||||
/**
|
||||
* PadN Hop-by-Hop TLV - 有数据部分
|
||||
*/
|
||||
public class PadNHopByHopTLV extends IPv6HopByHopTLV {
|
||||
public PadNHopByHopTLV(ByteBuffer klalbHeader) {
|
||||
super(klalbHeader);
|
||||
}
|
||||
|
||||
public PadNHopByHopTLV(int dataLength) {
|
||||
super(PadNHopByHopTLV.PADN);
|
||||
getData().limit(dataLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PadNHopByHopTLV [getDataLength()=" + getDataLength() + "]";
|
||||
}
|
||||
|
||||
|
||||
// 继承的readFromChannel和writeToChannel会正确处理数据部分
|
||||
}
|
||||
@@ -11,7 +11,32 @@ import org.kne.cloud.network.NetworkPacket;
|
||||
public class TLV extends NetworkPacket{
|
||||
|
||||
private int headerLength=2;
|
||||
|
||||
|
||||
public static final int PAD1=0;
|
||||
public TLV(ByteBuffer header, boolean isDefault) {
|
||||
this.header=header;
|
||||
this.isDefault=isDefault;
|
||||
if(getType()==PAD1)
|
||||
setHeaderLength(1);
|
||||
if(isDefault&&(getHeaderLength()>1)) {
|
||||
data=NetworkPacket.bufferAllocator.allocate(512);
|
||||
}
|
||||
}
|
||||
|
||||
public TLV(int type, boolean isDefault) {
|
||||
if(type==PAD1) {
|
||||
setHeaderLength(1);
|
||||
}
|
||||
this.header=NetworkPacket.bufferAllocator.allocate(getHeaderLength());
|
||||
this.isDefault=isDefault;
|
||||
header.put((byte) type);
|
||||
header.put((byte) 0);
|
||||
header.flip();
|
||||
if(isDefault&&(getHeaderLength()>1)) {
|
||||
data=NetworkPacket.bufferAllocator.allocate(512);
|
||||
}
|
||||
}
|
||||
|
||||
public int getHeaderLength() {
|
||||
return headerLength;
|
||||
}
|
||||
@@ -29,30 +54,31 @@ private int headerLength=2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return headerLength+(isDefault?data.limit():0);
|
||||
public long getTotalLength() {
|
||||
return getHeaderLength()+(isDefault?data.limit():0);
|
||||
}
|
||||
@Override
|
||||
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
||||
if(isDefault&&(headerLength>1)) {
|
||||
setDataLength(data.limit());
|
||||
}
|
||||
header.limit(headerLength);
|
||||
dto.write(header.slice(0,header.limit()));
|
||||
if(isDefault&&(headerLength>1)) {
|
||||
dto.write(data.slice(0, data.limit()));
|
||||
}
|
||||
if(isDefault&&(getHeaderLength()>1)) {
|
||||
setDataLength(data.limit());
|
||||
}
|
||||
header.limit(getHeaderLength());
|
||||
dto.write(header.slice(0,header.limit()));
|
||||
if(isDefault&&(getHeaderLength()>1)) {
|
||||
dto.write(data.slice(0, data.limit()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
||||
|
||||
header.limit(1);
|
||||
while (header.hasRemaining()) {
|
||||
if (din.read(header) == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
if(headerLength>1) {
|
||||
if(getHeaderLength()>1) {
|
||||
header.limit(2);
|
||||
while (header.hasRemaining()) {
|
||||
if (din.read(header) == -1) {
|
||||
@@ -62,7 +88,7 @@ private int headerLength=2;
|
||||
}
|
||||
header.flip();
|
||||
|
||||
if(isDefault&&(headerLength>1)) {
|
||||
if(isDefault&&(getHeaderLength()>1)) {
|
||||
data.clear();
|
||||
data.limit(getDataLength());
|
||||
while(data.hasRemaining()){
|
||||
@@ -93,4 +119,14 @@ private int headerLength=2;
|
||||
public void setDataLength(int dataLength) {
|
||||
header.put(1,(byte) dataLength);
|
||||
}
|
||||
|
||||
public void setHeaderLength(int headerLength) {
|
||||
this.headerLength = headerLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TLV [getType()=" + getType() + ", getDataLength()=" + getDataLength() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user