KLALB V3.4

This commit is contained in:
Administrator
2025-11-15 11:08:16 +08:00
parent 306bfd36f7
commit 8842566ee2
160 changed files with 18540 additions and 4512 deletions
@@ -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 自动生成的方法存根
}
};
+2 -2
View File
@@ -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会正确处理数据部分
}
+49 -13
View File
@@ -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() + "]";
}
}