First prototype vxlan hub

This commit is contained in:
Nadja Reitzenstein
2022-01-30 01:19:05 +01:00
committed by Kilobyte22
parent 7eb0d9efce
commit 40cfc418d6
7 changed files with 242 additions and 51 deletions

View File

@@ -47,9 +47,9 @@ public final class Config {
@Path("vxlan") public static boolean enable = false;
@Path("vxlan") public static String remoteHost = "::1";
@Path("vxlan") public static int remotePort = 4789;
@Path("vxlan") public static short remotePort = 4789;
@Path("vxlan") public static String bindHost = "::1";
@Path("vxlan") public static int bindPort = 4789;
@Path("vxlan") public static short bindPort = 4789;
public static boolean computersUseEnergy() {
return computerEnergyPerTick > 0 && computerEnergyStorage > 0;

View File

@@ -23,6 +23,7 @@ public final class Blocks {
public static final RegistryObject<NetworkHubBlock> NETWORK_HUB = BLOCKS.register("network_hub", NetworkHubBlock::new);
public static final RegistryObject<ProjectorBlock> PROJECTOR = BLOCKS.register("projector", ProjectorBlock::new);
public static final RegistryObject<RedstoneInterfaceBlock> REDSTONE_INTERFACE = BLOCKS.register("redstone_interface", RedstoneInterfaceBlock::new);
public static final RegistryObject<VxlanBlock> VXLAN_HUB = BLOCKS.register("vxlan_hub", VxlanBlock::new);
///////////////////////////////////////////////////////////////////

View File

@@ -1,35 +0,0 @@
package li.cil.oc2.common.block;
import li.cil.oc2.common.blockentity.BlockEntities;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import org.jetbrains.annotations.Nullable;
public class NetworkPortalBlock extends HorizontalDirectionalBlock implements EntityBlock {
public NetworkPortalBlock() {
super(Properties
.of(Material.METAL)
.sound(SoundType.METAL)
.strength(1.5f, 6.0f));
registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.NORTH));
}
@Override
public BlockState getStateForPlacement(final BlockPlaceContext context) {
return super.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
@Nullable
@Override
public BlockEntity newBlockEntity(final BlockPos pos, final BlockState state) {
return BlockEntities.NETWORK_HUB.get().create(pos, state);
}
}

View File

@@ -0,0 +1,62 @@
package li.cil.oc2.common.block;
import li.cil.oc2.common.blockentity.BlockEntities;
import li.cil.oc2.common.blockentity.NetworkHubBlockEntity;
import li.cil.oc2.common.blockentity.VxlanBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.material.Material;
import javax.annotation.Nullable;
public final class VxlanBlock extends HorizontalDirectionalBlock implements EntityBlock {
public VxlanBlock() {
super(Properties
.of(Material.METAL)
.sound(SoundType.METAL)
.strength(1.5f, 6.0f));
registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.NORTH));
}
///////////////////////////////////////////////////////////////////
@Override
public BlockState getStateForPlacement(final BlockPlaceContext context) {
return super.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}
@SuppressWarnings("deprecation")
@Override
public void neighborChanged(final BlockState state, final Level level, final BlockPos pos, final Block changedBlock, final BlockPos changedBlockPos, final boolean isMoving) {
final BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof final VxlanBlockEntity vxlanEntity) {
vxlanEntity.handleNeighborChanged();
}
}
///////////////////////////////////////////////////////////////////
// EntityBlock
@Nullable
@Override
public BlockEntity newBlockEntity(final BlockPos pos, final BlockState state) {
return BlockEntities.VXLAN_HUB.get().create(pos, state);
}
///////////////////////////////////////////////////////////////////
@Override
protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(FACING);
}
}

View File

@@ -26,6 +26,7 @@ public final class BlockEntities {
public static final RegistryObject<BlockEntityType<NetworkHubBlockEntity>> NETWORK_HUB = register(Blocks.NETWORK_HUB, NetworkHubBlockEntity::new);
public static final RegistryObject<BlockEntityType<ProjectorBlockEntity>> PROJECTOR = register(Blocks.PROJECTOR, ProjectorBlockEntity::new);
public static final RegistryObject<BlockEntityType<RedstoneInterfaceBlockEntity>> REDSTONE_INTERFACE = register(Blocks.REDSTONE_INTERFACE, RedstoneInterfaceBlockEntity::new);
public static final RegistryObject<BlockEntityType<VxlanBlockEntity>> VXLAN_HUB = register(Blocks.VXLAN_HUB, VxlanBlockEntity::new);
///////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,121 @@
package li.cil.oc2.common.blockentity;
import li.cil.oc2.api.capabilities.NetworkInterface;
import li.cil.oc2.common.Constants;
import li.cil.oc2.common.capabilities.Capabilities;
import li.cil.oc2.common.util.LazyOptionalUtils;
import li.cil.oc2.common.util.LevelUtils;
import li.cil.oc2.common.vxlan.TunnelManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.util.LazyOptional;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
public final class VxlanBlockEntity extends ModBlockEntity implements NetworkInterface {
private static final int TTL_COST = 1;
private int vti = ((int) (Math.random() * Integer.MAX_VALUE)) & 0x00ff_ffff;
private boolean initialized = false;
///////////////////////////////////////////////////////////////////
// Each face and the default TunnelInterface connecting to the outernet
private final NetworkInterface[] adjacentBlockInterfaces = new NetworkInterface[Constants.BLOCK_FACE_COUNT + 1];
private boolean haveAdjacentBlocksChanged = true;
///////////////////////////////////////////////////////////////////
public VxlanBlockEntity(final BlockPos pos, final BlockState state) {
super(BlockEntities.NETWORK_HUB.get(), pos, state);
}
///////////////////////////////////////////////////////////////////
public void handleNeighborChanged() {
haveAdjacentBlocksChanged = true;
}
@Override
public byte[] readEthernetFrame() {
return null;
}
@Override
public void writeEthernetFrame(final NetworkInterface source, final byte[] frame, final int timeToLive) {
getAdjacentInterfaces().forEach(adjacentInterface -> {
if (adjacentInterface != source) {
adjacentInterface.writeEthernetFrame(this, frame, timeToLive - TTL_COST);
}
});
}
///////////////////////////////////////////////////////////////////
@Override
public void load(CompoundTag tag) {
super.load(tag);
vti = tag.getInt("vti");
}
@Override
protected void onUnload(final boolean isRemove) {
TunnelManager.instance().unregisterVti(vti);
super.onUnload(isRemove);
}
@Override
public void onLoad() {
super.onLoad();
TunnelManager.instance().registerVti(vti, this);
}
///////////////////////////////////////////////////////////////////
@Override
protected void collectCapabilities(final CapabilityCollector collector, @Nullable final Direction direction) {
collector.offer(Capabilities.NETWORK_INTERFACE, this);
}
///////////////////////////////////////////////////////////////////
private Stream<NetworkInterface> getAdjacentInterfaces() {
validateAdjacentBlocks();
return Arrays.stream(adjacentBlockInterfaces).filter(Objects::nonNull);
}
private void validateAdjacentBlocks() {
if (isRemoved() || !haveAdjacentBlocksChanged) {
return;
}
for (final Direction side : Constants.DIRECTIONS) {
adjacentBlockInterfaces[side.get3DDataValue() + 1] = null;
}
haveAdjacentBlocksChanged = false;
if (level == null || level.isClientSide()) {
return;
}
final BlockPos pos = getBlockPos();
for (final Direction side : Constants.DIRECTIONS) {
final BlockEntity neighborBlockEntity = LevelUtils.getBlockEntityIfChunkExists(level, pos.relative(side));
if (neighborBlockEntity != null) {
final LazyOptional<NetworkInterface> optional = neighborBlockEntity.getCapability(Capabilities.NETWORK_INTERFACE, side.getOpposite());
optional.ifPresent(adjacentInterface -> {
adjacentBlockInterfaces[side.get3DDataValue() + 1] = adjacentInterface;
LazyOptionalUtils.addWeakListener(optional, this, (hub, unused) -> hub.handleNeighborChanged());
});
}
}
}
}

View File

@@ -2,6 +2,7 @@ package li.cil.oc2.common.vxlan;
import li.cil.oc2.api.capabilities.NetworkInterface;
import li.cil.oc2.common.Config;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.*;
@@ -9,11 +10,19 @@ import java.util.HashMap;
public class TunnelManager {
private final HashMap<Integer, NetworkInterface> tunnels = new HashMap<>();
private final HashMap<Integer, TunnelInterface> tunnels = new HashMap<>();
private final DatagramSocket socket;
private static TunnelManager INSTANCE;
private final InetAddress remoteHost;
private final short remotePort;
private final InetAddress bindHost;
private final short bindPort;
public TunnelManager(InetAddress bindHost, short bindPort, InetAddress remoteHost, short remotePort) throws SocketException {
this.remoteHost = remoteHost;
this.remotePort = remotePort;
this.bindHost = bindHost;
this.bindPort = bindPort;
socket = new DatagramSocket(bindPort, bindHost);
socket.connect(remoteHost, remotePort);
}
@@ -29,12 +38,7 @@ public class TunnelManager {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
INSTANCE.listen();
}
}).start();
new Thread(() -> INSTANCE.listen()).start();
}
}
@@ -50,19 +54,21 @@ public class TunnelManager {
}
byte flags = packet.getData()[0];
int vni_1 = packet.getData()[4];
int vni = packet.getData()[6]
+ packet.getData()[5] << 8
+ packet.getData()[4] << 16;
if ((flags & 0x08) != 0x08) {
continue;
}
NetworkInterface iface = tunnels.get(vni);
TunnelInterface iface = tunnels.get(vni);
if (iface != null) {
byte[] inner = new byte[packet.getData().length - 8];
copyBytes(packet.getData(), inner, 8, 0, packet.getData().length - 8);
System.arraycopy(packet.getData(), 8, inner, 0, packet.getData().length - 8);
iface.writeEthernetFrame(null, inner, 255);
iface.target.writeEthernetFrame(iface, inner, 255);
}
}
} catch (IOException e) {
@@ -74,9 +80,44 @@ public class TunnelManager {
return INSTANCE;
}
private void copyBytes(byte[] input, byte[] output, int inputOffset, int outputOffset, int length) {
for (int i = 0; i < length; i++) {
output[outputOffset + i] = input[inputOffset + i];
public void sendToVti(int vti, byte[] payload) {
byte[] buffer = new byte[payload.length + 8];
System.arraycopy(payload, 0, buffer, 8, payload.length);
buffer[0] = 0x08;
buffer[4] = (byte) ((vti >> 16) & 0xff);
buffer[5] = (byte) ((vti >> 8) & 0xff);
buffer[6] = (byte) (vti & 0xff);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, this.remoteHost, this.remotePort);
}
public void registerVti(int vti, NetworkInterface iface) {
tunnels.put(vti, new TunnelInterface(vti, iface));
}
public void unregisterVti(int vti) {
tunnels.remove(vti);
}
public class TunnelInterface implements NetworkInterface {
final NetworkInterface target;
private final int vti;
public TunnelInterface(int vti, NetworkInterface iface) {
this.vti = vti;
this.target = iface;
}
@Override
public byte[] readEthernetFrame() {
return new byte[0];
}
@Override
public void writeEthernetFrame(final NetworkInterface source, final byte[] frame, final int timeToLive) {
TunnelManager.this.sendToVti(vti, frame);
}
}
}