Skip to content

Commit

Permalink
Ipv4: Added enableLocalOutMulticastRouting NED parameter.
Browse files Browse the repository at this point in the history
Also inlined determineOutgoingInterfaceForMulticastDatagram into datagramLocalOut.
  • Loading branch information
levy committed Jan 12, 2024
1 parent db2408d commit 109fd67
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 42 deletions.
100 changes: 63 additions & 37 deletions src/inet/networklayer/ipv4/Ipv4.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ void Ipv4::initialize(int stage)
limitedBroadcast = par("limitedBroadcast");
directBroadcastInterfaces = par("directBroadcastInterfaces").stdstringValue();
directBroadcastInterfaceMatcher.setPattern(directBroadcastInterfaces.c_str(), false, true, false);
enableLocalOutMulticastRouting = par("enableLocalOutMulticastRouting");
enableTimestampOption = par("enableTimestampOption");
maxLifetime = par("maxLifetime");

Expand Down Expand Up @@ -432,10 +433,54 @@ void Ipv4::datagramLocalOut(Packet *packet)
EV_DETAIL << "Sending datagram '" << packet->getName() << "' with destination = " << destAddr << "\n";

if (ipv4Header->getDestAddress().isMulticast()) {
const Ipv4Address srcAddr = ipv4Header->getSrcAddress();
const Ipv4MulticastRoute *route = rt->findBestMatchingMulticastRoute(srcAddr, destAddr);
if (route) {
// RFC 1112, section 6.1
//"
// Second, for hosts that may be attached to more than one network, the
// service interface should provide a way for the upper-layer protocol
// to identify which network interface is be used for the multicast
// transmission. Only one interface is used for the initial
// transmission; multicast routers are responsible for forwarding to any
// other networks, if necessary. If the upper-layer protocol chooses
// not to identify an outgoing interface, a default interface should be
// used, preferably under the control of system management.
//"
// INET also provides optional non-standard behavior to use the multicast
// routing table if enabled. This allows multicast packets to go out on
// several network interfaces.
if (destIE) {
// use the interface specified by MULTICAST_IF socket option
numMulticast++;
EV_DETAIL << "multicast packet routed to requested output interface " << destIE->getInterfaceName() << "\n";

// loop back a copy
if (multicastLoop && !destIE->isLoopback()) {
const NetworkInterface *loopbackIF = ift->findFirstLoopbackInterface();
if (loopbackIF) {
auto packetCopy = packet->dup();
packetCopy->addTagIfAbsent<InterfaceReq>()->setInterfaceId(loopbackIF->getInterfaceId());
packetCopy->addTagIfAbsent<NextHopAddressReq>()->setNextHopAddress(destAddr);
fragmentPostRouting(packetCopy);
}
}

packet->addTagIfAbsent<InterfaceReq>()->setInterfaceId(destIE->getInterfaceId());
packet->addTagIfAbsent<NextHopAddressReq>()->setNextHopAddress(destAddr);
fragmentPostRouting(packet);
}
else if (auto route = enableLocalOutMulticastRouting ? rt->findBestMatchingMulticastRoute(ipv4Header->getSrcAddress(), destAddr) : nullptr) {
numMulticast++;

// loop back a copy
if (multicastLoop) {
const NetworkInterface *loopbackIF = ift->findFirstLoopbackInterface();
if (loopbackIF) {
auto packetCopy = packet->dup();
packetCopy->addTagIfAbsent<InterfaceReq>()->setInterfaceId(loopbackIF->getInterfaceId());
packetCopy->addTagIfAbsent<NextHopAddressReq>()->setNextHopAddress(destAddr);
fragmentPostRouting(packetCopy);
}
}

// copy original datagram for multiple destinations
for (unsigned int i = 0; i < route->getNumOutInterfaces(); i++) {
Ipv4MulticastRoute::OutInterface *outInterface = route->getOutInterface(i);
Expand All @@ -457,7 +502,21 @@ void Ipv4::datagramLocalOut(Packet *packet)
delete packet;
}
else {
destIE = determineOutgoingInterfaceForMulticastDatagram(ipv4Header, destIE);
// try to lookup the multicast address in the unicast routing table
if (auto route = rt->findBestMatchingRoute(ipv4Header->getDestAddress())) {
destIE = route->getInterface();
EV_DETAIL << "multicast packet routed to output interface " << destIE->getInterfaceName() << " by dest address lookup in the unicast routing table\n";
}
if (!destIE) {
destIE = rt->getInterfaceByAddress(ipv4Header->getSrcAddress());
if (destIE)
EV_DETAIL << "multicast packet routed to output interface " << destIE->getInterfaceName() << " identified by source address\n";
}
if (!destIE) {
destIE = ift->findFirstMulticastInterface();
if (destIE)
EV_DETAIL << "multicast packet routed to the first multicast interface " << destIE->getInterfaceName() << "\n";
}

// loop back a copy
if (multicastLoop && (!destIE || !destIE->isLoopback())) {
Expand Down Expand Up @@ -519,39 +578,6 @@ void Ipv4::datagramLocalOut(Packet *packet)
}
}

/* Choose the outgoing interface for the muticast datagram:
* 1. use the interface specified by MULTICAST_IF socket option (received in the control info)
* 2. lookup the destination address in the routing table
* 3. if no route, choose the interface according to the source address
* 4. or if the source address is unspecified, choose the first MULTICAST interface
*/
const NetworkInterface *Ipv4::determineOutgoingInterfaceForMulticastDatagram(const Ptr<const Ipv4Header>& ipv4Header, const NetworkInterface *multicastIFOption)
{
const NetworkInterface *ie = nullptr;
if (multicastIFOption) {
ie = multicastIFOption;
EV_DETAIL << "multicast packet routed by socket option via output interface " << ie->getInterfaceName() << "\n";
}
if (!ie) {
Ipv4Route *route = rt->findBestMatchingRoute(ipv4Header->getDestAddress());
if (route)
ie = route->getInterface();
if (ie)
EV_DETAIL << "multicast packet routed by routing table via output interface " << ie->getInterfaceName() << "\n";
}
if (!ie) {
ie = rt->getInterfaceByAddress(ipv4Header->getSrcAddress());
if (ie)
EV_DETAIL << "multicast packet routed by source address via output interface " << ie->getInterfaceName() << "\n";
}
if (!ie) {
ie = ift->findFirstMulticastInterface();
if (ie)
EV_DETAIL << "multicast packet routed via the first multicast interface " << ie->getInterfaceName() << "\n";
}
return ie;
}

void Ipv4::routeUnicastPacket(Packet *packet)
{
const NetworkInterface *fromIE = getSourceInterface(packet);
Expand Down
6 changes: 1 addition & 5 deletions src/inet/networklayer/ipv4/Ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class INET_API Ipv4 : public OperationalBase, public NetfilterBase, public INetw
simtime_t fragmentTimeoutTime;
bool limitedBroadcast = false;
std::string directBroadcastInterfaces = "";
bool enableLocalOutMulticastRouting = false;
bool enableTimestampOption = false;
simtime_t maxLifetime = -1;

Expand Down Expand Up @@ -162,11 +163,6 @@ class INET_API Ipv4 : public OperationalBase, public NetfilterBase, public INetw
*/
virtual void routeLocalBroadcastPacket(Packet *packet);

/**
* Determines the output interface for the given multicast datagram.
*/
virtual const NetworkInterface *determineOutgoingInterfaceForMulticastDatagram(const Ptr<const Ipv4Header>& ipv4Header, const NetworkInterface *multicastIFOption);

/**
* Forwards packets to all multicast destinations, using fragmentAndSend().
*/
Expand Down
1 change: 1 addition & 0 deletions src/inet/networklayer/ipv4/Ipv4.ned
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ simple Ipv4 like IIpv4
double fragmentTimeout @unit(s) = default(60s);
bool limitedBroadcast = default(false); // send out limited broadcast packets comming from higher layer
string directBroadcastInterfaces = default(""); // list of interfaces that direct broadcast is enabled (by default direct broadcast is disabled on all interfaces)
bool enableLocalOutMulticastRouting = default(false); // enable using the multicast routing table for determining outgoing interfaces for local out packets
bool enableTimestampOption = default(false); // when enabled IP inserts a timestamp option into the IP header
double maxLifetime @unit(s) = default(-1s); // packets older than the limit are discarded
@display("i=block/routing");
Expand Down

0 comments on commit 109fd67

Please sign in to comment.