Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sns): support multi-hop unicast for topological and geographical routing #428

Merged
merged 2 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

Expand Down Expand Up @@ -93,23 +92,20 @@ Map<String, TransmissionResult> preProcessInteraction(V2xMessageTransmission int
switch (dac.getType()) {
case AD_HOC_TOPOCAST:
if (log.isDebugEnabled()) {
log.debug(
"Send v2xMessage.id={} from node={} as Topocast (singlehop) @time={}",
log.debug("Send v2xMessage.id={} from node={} as Topocast (singlehop) @time={}",
interaction.getMessage().getId(), senderName, TIME.format(interaction.getTime())
);
}
return sendMessageAsTopocast(senderName, dac);
case AD_HOC_GEOCAST:
if (log.isDebugEnabled()) {
log.debug(
"Send v2xMessage.id={} from={} as Geocast (geo routing) @time={}",
log.debug( "Send v2xMessage.id={} from={} as Geocast (geo routing) @time={}",
interaction.getMessage().getId(), senderName, TIME.format(interaction.getTime())
);
}
return sendMessageAsGeocast(senderName, dac);
default:
log.debug(
"V2XMessage is not an ad hoc message. Skip this message. V2XMessage.id={}",
log.debug("V2XMessage is not an ad hoc message. Skip this message. V2XMessage.id={}",
interaction.getMessage().getId()
);
return null;
Expand Down Expand Up @@ -137,101 +133,115 @@ private boolean isValidSender(String senderName) {
}

/**
* Simulates topolocically-scoped Unicast or Broadcast as direct singlehop transmission.
* (NO multi-hops are implemented by now)
* <ol>
* <li>Verify if configured transmission can be send using the topocast logic
* <li>Differentiate between Unicast and Broadcast
* <li>Simulate transmission with one hop
* </ol>
* Simulates topolocically-scoped Unicast (singlehop or multihop transmissions) or Broadcast (only singlehop).
*
* @param senderName The Sender of the message.
* @param dac {@link DestinationAddressContainer} containing information about the destination for the message.
* @return a Map containing the summarized transmission results
*/
protected Map<String, TransmissionResult> sendMessageAsTopocast(String senderName, DestinationAddressContainer dac) {
NetworkAddress destinationAddress = dac.getAddress();
if (destinationAddress.isAnycast()) { // check for valid destination address
log.warn(
"The SNS only supports SingleHopBroadCasts or SingleHopUniCasts when using TopoCasts."
+ " The given destination address {} is not valid. No message will be send.",
destinationAddress
);
return null;
}
if (dac.getTimeToLive() != SINGLE_HOP_TTL) { // inform about dismissed TTL
log.debug("TTL {} will be dismissed and 1 will be used instead. For Topocast, SNS only supports SingleHopBroadCasts.", dac.getTimeToLive());
}
final NetworkAddress destinationAddress = dac.getAddress();

// accumulate all potential receivers in direct communication range
SimulationNode sender = SimulationEntities.INSTANCE.getOnlineNode(senderName);
Map<String, SimulationNode> allPotentialReceivers;
if (destinationAddress.isBroadcast()) { // SingleHopBroadCast
allPotentialReceivers = getPotentialBroadcastReceivers(getTopocastDestinationArea(sender));
// remove sender as single radios could not transmit and receive at the same time
allPotentialReceivers.remove(senderName);
} else { // SingleHopUniCast
allPotentialReceivers = getAddressedReceiver(destinationAddress, getTopocastDestinationArea(sender));
if (destinationAddress.isBroadcast() && dac.getTimeToLive() != SINGLE_HOP_TTL) {
log.warn("SNS only supports single hop broadcasts. TTL {} will be dismissed and 1 will be used instead.", dac.getTimeToLive());
}
log.debug("Addressed nodes in destination area={}", allPotentialReceivers);

// perform actual transmission
TransmissionParameter transmissionParameter = new TransmissionParameter(
final TransmissionParameter transmissionParameter = new TransmissionParameter(
randomNumberGenerator,
config.singlehopDelay,
config.singlehopTransmission,
SINGLE_HOP_TTL
);
return transmissionModel.simulateTopocast(
senderName, allPotentialReceivers, transmissionParameter, SimulationEntities.INSTANCE.getAllOnlineNodes()
getTtl(dac)
);
// accumulate all potential receivers in direct communication range
final SimulationNode sender = SimulationEntities.INSTANCE.getOnlineNode(senderName);

if (destinationAddress.isBroadcast()) { // SingleHopBroadCast
final var allPotentialReceivers = getPotentialBroadcastReceivers(getTopocastDestinationArea(sender));
// remove sender as single radios could not transmit and receive at the same time
allPotentialReceivers.remove(senderName);
log.debug("Addressed nodes in destination area={}", allPotentialReceivers);
// transmission via singlehop broadcast
return transmissionModel.simulateTopologicalSinglehop(
senderName, allPotentialReceivers, transmissionParameter, SimulationEntities.INSTANCE.getAllOnlineNodes()
);
} else if (destinationAddress.isUnicast()) {
final String destinationNodeId = IpResolver.getSingleton().reverseLookup(destinationAddress.getIPv4Address());
final SimulationNode destination = SimulationEntities.INSTANCE.getOnlineNode(destinationNodeId);

final boolean isInAreaOfSender = isNodeInArea(destination.getPosition(), getTopocastDestinationArea(sender));
if (isInAreaOfSender) {
return transmissionModel.simulateTopologicalSinglehop(
senderName, Map.of(destinationNodeId, destination), transmissionParameter, SimulationEntities.INSTANCE.getAllOnlineNodes()
);
} else {
final TransmissionResult result = transmissionModel.simulateTopologicalUnicast(
senderName, destinationNodeId, destination, transmissionParameter, SimulationEntities.INSTANCE.getAllOnlineNodes()
);
return Map.of(destinationNodeId, result);
}
} else {
log.warn("""
The SNS only supports SingleHop BroadCasts or MultiHop UniCasts when using Topological routing."
The given destination address {} is not valid. No message will be send.""", destinationAddress
);
return Map.of();
}
}

/**
* Simulates geocast routing transmission.
* (ONLY Broadcasts are implemented by now)
* <ol>
* <li>Verify if configured transmission can be send using the topocast logic
* <li>determine all potential receiver nodes in the destination area
* (including original sender due to re-broadcasting in geocast)</li>
* <li>simulate message transmission via
* <ol type="a">
* <li>simplified Multihop mode (possibly needed hops to reach destination not regarded)
* <li>with more elaborated approaching and flooding modes
* </ol>
* </ol>
* Simulates geocast routing transmission, either broadcast or unicast.
*
* @param senderName The Sender of the message.
* @param dac {@link DestinationAddressContainer} containing information about the destination for the message.
* @return a Map containing the summarized transmission results
*/
protected Map<String, TransmissionResult> sendMessageAsGeocast(String senderName, DestinationAddressContainer dac) {
if (dac.getGeoArea() == null) {
return Collections.EMPTY_MAP;
log.error("No target area given for Geographic routing. No message will be send.");
return Map.of();
}
final NetworkAddress destinationAddress = dac.getAddress();
final Area<CartesianPoint> destinationArea = dac.getGeoArea().toCartesian();

Area<CartesianPoint> destinationArea = dac.getGeoArea().toCartesian();
Map<String, SimulationNode> allReceivers = getPotentialBroadcastReceivers(destinationArea);
log.debug("Addressed nodes in destination area={}", allReceivers);

// get ttl value, this will be ignored for the simple transmission model
int ttl;
if (dac.getTimeToLive() == -1) {
ttl = config.maximumTtl; // ttl was null, which is interpreted as maximum
final Map<String, SimulationNode> allReceivers;
if (destinationAddress.isUnicast()) {
final String destinationNodeId = IpResolver.getSingleton().reverseLookup(destinationAddress.getIPv4Address());
if (getPotentialBroadcastReceivers(destinationArea).containsKey(destinationNodeId)) {
allReceivers = Map.of(destinationNodeId, SimulationEntities.INSTANCE.getOnlineNode(destinationNodeId));
} else {
return Map.of();
}
} else if (destinationAddress.isBroadcast()){
allReceivers = getPotentialBroadcastReceivers(destinationArea);
log.debug("Addressed nodes in destination area={}", allReceivers);
} else {
ttl = Math.min(dac.getTimeToLive(), config.maximumTtl); // ttl can't be higher than maximumTtl
log.warn("""
The SNS only supports BroadCasts or UniCasts when using geograpical routing."
The given destination address {} is not valid. No message will be send.""", destinationAddress
);
return Map.of();
}
TransmissionParameter transmissionParameter = new TransmissionParameter(

// get ttl value, this will be ignored for the simple transmission model
final TransmissionParameter transmissionParameter = new TransmissionParameter(
randomNumberGenerator,
config.singlehopDelay,
config.singlehopTransmission,
ttl
getTtl(dac)
);
return transmissionModel.simulateGeocast(
senderName, allReceivers, transmissionParameter, SimulationEntities.INSTANCE.getAllOnlineNodes()
);
}

private int getTtl(DestinationAddressContainer dac) {
if (dac.getTimeToLive() == -1) {
return config.maximumTtl;
} else {
return Math.min(dac.getTimeToLive(), config.maximumTtl);
}
}

private Area<CartesianPoint> getTopocastDestinationArea(SimulationNode nodeData) {
return new CartesianCircle(nodeData.getPosition(), nodeData.getRadius());
}
Expand All @@ -242,7 +252,7 @@ private Area<CartesianPoint> getTopocastDestinationArea(SimulationNode nodeData)
* @param destinationArea destination area for transmission
* @return a map containing the
*/
private Map<String, SimulationNode> getPotentialBroadcastReceivers(Area<CartesianPoint> destinationArea) {
private static Map<String, SimulationNode> getPotentialBroadcastReceivers(Area<CartesianPoint> destinationArea) {
return getEntitiesInArea(SimulationEntities.INSTANCE.getAllOnlineNodes(), destinationArea);
}

Expand All @@ -255,37 +265,16 @@ private Map<String, SimulationNode> getPotentialBroadcastReceivers(Area<Cartesia
* It is called "range" because it reflects the communication range
* @return A map of the given entities, which are in the destination area.
*/
public static Map<String, SimulationNode> getEntitiesInArea(
Map<String, SimulationNode> relevantEntities, Area<CartesianPoint> range) {
Map<String, SimulationNode> results = new HashMap<>();

for (Map.Entry<String, SimulationNode> entityEntry : relevantEntities.entrySet()) {
public static Map<String, SimulationNode> getEntitiesInArea(Map<String, SimulationNode> relevantEntities, Area<CartesianPoint> range) {
final Map<String, SimulationNode> results = new HashMap<>();
for (var entityEntry : relevantEntities.entrySet()) {
if (range.contains(entityEntry.getValue().getPosition())) {
results.put(entityEntry.getKey(), entityEntry.getValue());
}
}
return results;
}

/**
* Returns the addressed receiver, if it is known inside the destination area (more specific check compared to broadcast).
* Note: The resulting Map will always contain 0 or 1 elements.
*
* @param destinationAddress address of the potential receiver
* @param reachableArea area, that can be reached with one hop by the sender
* @return if receiver was found single element map, else empty map
*/
private Map<String, SimulationNode> getAddressedReceiver(NetworkAddress destinationAddress, Area<CartesianPoint> reachableArea) {
final Map<String, SimulationNode> receiver = new HashMap<>();

final String destinationNodeId = IpResolver.getSingleton().reverseLookup(destinationAddress.getIPv4Address());
SimulationNode entity = SimulationEntities.INSTANCE.getOnlineNode(destinationNodeId);
if (entity != null && isNodeInArea(entity.getPosition(), reachableArea)) {
receiver.put(destinationNodeId, entity);
}
return receiver;
}

private boolean isNodeInArea(CartesianPoint nodePosition, Area<CartesianPoint> destinationArea) {
if (nodePosition == null) {
log.warn("position of the unit is null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,45 @@ public abstract class AdhocTransmissionModel {
* @return A {@link TransmissionResult} calculated using the given parameters
*/
TransmissionResult simulateTransmission(RandomNumberGenerator randomNumberGenerator, Delay delay, CTransmission transmission) {
TransmissionResult result =
TransmissionModel.simulateTransmission(randomNumberGenerator, transmission.lossProbability, transmission.maxRetries);
TransmissionResult result = TransmissionModel.simulateTransmission(
randomNumberGenerator, transmission.lossProbability, transmission.maxRetries
);
result.delay = delay.generateDelay(randomNumberGenerator, 0); // speed of node is only relevant for not-supported GammaSpeedDelay
result.numberOfHops += 1;
return result;
}

/**
* Method to be implemented by extensions of {@link AdhocTransmissionModel}, calculating transmissions using topocast.
* Method to be implemented by extensions of {@link AdhocTransmissionModel}, calculating transmissions using topocast with
* only one single hop, either broadcast or unicast.
*
* @param senderName The sender of the transmission.
* @param receivers The receivers of the transmission.
* @param transmissionParameter Data class holding the maximumTtl, the {@link Delay} and the current map of simulated entities
* @param currentNodes a reference to all currently online nodes
* @return Map of the receivers and their transmission results.
*/
public abstract Map<String, TransmissionResult> simulateTopocast(
public abstract Map<String, TransmissionResult> simulateTopologicalSinglehop(
String senderName, Map<String, SimulationNode> receivers,
TransmissionParameter transmissionParameter, Map<String, SimulationNode> currentNodes
);

/**
* Method to be implemented by extensions of {@link AdhocTransmissionModel}, calculating transmissions using topocast
* with multiple hops, only unicast.
*
* @param senderName The sender of the transmission.
* @param receiverName The receivers of the unicast transmission.
* @param receiver The receiver node information of the unicast transmission.
* @param transmissionParameter Data class holding the maximumTtl, the {@link Delay} and the current map of simulated entities
* @param currentNodes a reference to all currently online nodes
* @return The transmission result to the single receiver.
*/
public abstract TransmissionResult simulateTopologicalUnicast(
String senderName, String receiverName, SimulationNode receiver,
TransmissionParameter transmissionParameter, Map<String, SimulationNode> currentNodes
);

/**
* Method to be implemented by extensions of {@link AdhocTransmissionModel}, calculating transmissions using geocast.
*
Expand Down
Loading
Loading